标签:
基于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