基于TCP---通讯模型
由上图可以得出TCP通讯的步骤如下:
服务端:
1、创建一个socket,用函数socket();
2、绑定IP地址、端口等信息到socket上,用函数bind();
3、设置允许的最大连接数,用函数listen();
4、等待来着客户端的连接请求,用函数accept();
5、收发数据,用函数send()和recv(),或者read()和write();
6、关闭网络连接;
客户端:
1、创建一个socket,用函数socket;
2、设置要连接的服务器的IP地址和端口等属性;
3、连接服务器,用函数connect();
4、收发数据,用函数send()和recv(),或者read()和write();
5、关闭网络连接;
示例程序如下:
服务端:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#define PROT_NUMBER 3333
#define LINK_NUMBER 20
#define BUF_SIZE 1024
int main(int argc, char *argv[]){
int server_fd, new_sockfd, sin_size;
struct sockaddr_in server_addr,client_addr;
char buf[BUF_SIZE] = {0};
bzero(&server_addr, sizeof(struct sockaddr_in));
bzero(&client_addr, sizeof(struct sockaddr_in));
//创建socket套结字
server_fd = socket(AF_INET,SOCK_STREAM,0);/*AF_INET:IPv4;SOCKET_STREAM: TCP*/
if(server_fd == -1){
fprintf(stderr, "Socket Error %s\n\a", strerror(errno));
exit(EXIT_FAILURE);
}
//填充socket套结字
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PROT_NUMBER);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//绑定套结字
if((bind(server_fd, (struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in))) == -1){
fprintf(stderr, "Bind Error %s\n\a", strerror(errno));
exit(EXIT_FAILURE);
}
//设置最大连接数
if((listen(server_fd, LINK_NUMBER)) == -1){
fprintf(stderr, "Listen Error %s\n\a", strerror(errno));
exit(EXIT_FAILURE);
}
sin_size = sizeof(struct sockaddr_in);
//服务器阻塞,等待客户端链接
if((new_sockfd = accept(server_fd,(struct sockaddr *)(&client_addr),&sin_size)) == -1){
fprintf(stderr, "Accept Error %s\n\a", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr));
while(1){
//接收客户端发送的内容
if((recv(new_sockfd,buf,BUF_SIZE,0)) == -1){
fprintf(stderr, "Recv Error %s\n\a", strerror(errno));
exit(EXIT_FAILURE);
}
else if(*buf == '\0'){
break;
}
printf("Server received %s\n",buf);
bzero(&buf,BUF_SIZE);
}
close(server_fd);
return 0;
}客户端:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#define SERVER_PORT 3333
#define BUF_SIZE 1024
int main(int argc, char *argv[]){
if(argc != 2){
printf("Usage: %s hostname\n",argv[0]);
exit(EXIT_FAILURE);
}
int client_fd;
struct sockaddr_in server_addr;
struct hostent *host;
char buf[BUF_SIZE] = {0};
bzero(&server_addr,sizeof(struct sockaddr_in));
//通过域名得到IP
if((host = gethostbyname(argv[1])) == NULL){
switch(h_errno)
{
case HOST_NOT_FOUND :
printf("The specified host is unknown\n");
break;
case NO_ADDRESS:
printf("The requested name is valid but does not have an IP address.\n");
break;
case NO_RECOVERY:
printf(" A nonrecoverable name server error occurred.\n");
break;
case TRY_AGAIN:
printf("A temporary error occurred in the authoritative domain name server. Please try again later.\n");
break;
}
exit(EXIT_FAILURE);
}
//创建套结字
client_fd = socket(AF_INET, SOCK_STREAM , 0);
if(client_fd == -1){
fprintf(stderr,"Socket error:%s",strerror(errno));
exit(EXIT_FAILURE);
}
//填充服务端sockaddr结构
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr = *((struct in_addr*)host->h_addr);
//连接服务器
if((connect(client_fd, (struct sockaddr *)(&server_addr),sizeof(struct sockaddr_in))) == -1){
fprintf(stderr,"Connect error:%s",strerror(errno));
exit(EXIT_FAILURE);
}
while(1){
scanf("%s",buf);
if(strcmp(buf,"Quit") == 0){
break;
}
//发送数据
if((send(client_fd,buf,sizeof(buf),0)) == -1){
fprintf(stderr,"Connect error:%s",strerror(errno));
exit(EXIT_FAILURE);
}
}
close(client_fd);
}
总结:
1、填充sockaddr结构体时,注意字节序;
2、服务端的阻塞位置 accept (等待客户端) recv (接收时的阻塞);
原文:http://blog.csdn.net/u011641885/article/details/46591825