3.4 多路复用IO解决TCP协议下并发性问题
head.h
1 #ifndef _HEAD_H_ 2 #define _HEAD_H_ 3 4 #include<stdio.h> 5 #include<stdlib.h> 6 #include<string.h> 7 #include<sys/types.h> 8 #include<sys/socket.h> 9 #include<arpa/inet.h> 10 #include<netinet/in.h> 11 #include<netinet/ip.h> 12 #include<unistd.h> 13 #include<sys/stat.h> 14 #include<fcntl.h> 15 #include<error.h> 16 #include<errno.h> 17 18 #define error_exit(_errmsg_) error(EXIT_FAILURE,errno,_errmsg_) 19 #define SER_PORT 50008 20 #define SER_ADDR "192.168.239.129" 21 22 #endif
Makefile
1 ALL:client server 2 client:client.c 3 gcc $< -o $@ 4 server:server.c 5 gcc $< -o $@ 6 .PHONY: 7 clean: rm client server
client.c
1 //多路复用IO解决TCP协议下并发性问题 2 #include"head.h" 3 int main()//client 4 { 5 char buff[1024]="hello world!"; 6 char buff0[1024]={0}; 7 char buff1[1024]={0};//buff1与buff可一样,覆盖 8 char i=1; 9 10 int sockfd=0; 11 struct sockaddr_in seraddr; 12 seraddr.sin_family=AF_INET; 13 seraddr.sin_port=htons(SER_PORT); 14 seraddr.sin_addr.s_addr=inet_addr(SER_ADDR); 15 16 if(-1==(sockfd=socket(AF_INET,SOCK_STREAM,0))) 17 error_exit("fail to socket!"); 18 if(-1==connect(sockfd,(struct sockaddr* )&seraddr,sizeof(seraddr))) 19 error_exit("fail to connect!"); 20 //发送 21 while(1) 22 { 23 sprintf(buff0,"%s----%d---",buff,i); 24 //sprintf(buff0,"hello world!---%d---",i); 25 if(-1==send(sockfd,buff0,strlen(buff0)+1,0)) 26 error_exit("fail to send!"); 27 if(-1==recv(sockfd,buff1,sizeof(buff1),0))//一般客户端中端 28 error_exit("fail to recv!"); 29 i++; 30 printf("REPLY:%s\n",buff1); 31 sleep(1); 32 } 33 close(sockfd); 34 return 0; 35 }
server.c
1 //多路复用IO解决TCP协议下并发性问题 2 #include"head.h" 3 int main()//server 4 { 5 int confd=0; 6 int i=0; 7 char buff[1024]={0}; 8 9 fd_set rdfds,tmpfds;//定义读文件描述符集合和备份 10 int maxfd=0;//最大文件描述符+1为nfds 11 12 int sockfd=0; 13 struct sockaddr_in seraddr,cltaddr; 14 socklen_t addrlen=sizeof(cltaddr); 15 seraddr.sin_family=AF_INET; 16 seraddr.sin_port=htons(SER_PORT); 17 seraddr.sin_addr.s_addr=inet_addr(SER_ADDR); 18 //创建用来通信的文件描述符/为自己申请资源 19 if(-1==(sockfd=socket(AF_INET,SOCK_STREAM,0))) 20 error_exit("fail to socket!"); 21 //将文件描述符sockfd和IP地址绑定 22 if(-1==bind(sockfd,(struct sockaddr* )&seraddr,sizeof(seraddr))) 23 error_exit("fail to bind!"); 24 //指定链接请求队列的长度 25 if(-1==listen(sockfd,10)) 26 error_exit("fail to listen!"); 27 // 28 FD_ZERO(&rdfds); 29 FD_SET(sockfd,&rdfds); 30 maxfd=sockfd+1; 31 //maxfd=sockfd; 32 tmpfds=rdfds;//备份 33 34 while(1) 35 { 36 rdfds=tmpfds;// 37 //监听多个文件描述符集合,一旦有一个来数据后所对应的文件描述符阻塞,其他被剔除 38 select(maxfd,&rdfds,NULL,NULL,NULL); 39 if(FD_ISSET(sockfd,&rdfds))//判断是否有客户端来数据来链接服务器 40 { 41 if(-1==(confd=accept(sockfd,NULL,NULL)))//用confd收取申请链接的客户端的文件描述符/accept阻塞等待功能 42 error_exit("fail to accept!"); 43 FD_SET(confd,&tmpfds);//将接收到的客户端文件描述符加入到文件描述符集合当中 44 maxfd =( maxfd > confd) ? maxfd : (confd+1);//如果有客户端来数据则有文件描述符的值被赋予maxfd 45 } 46 for(i=4;i<maxfd;i++) 47 { 48 if(FD_ISSET(i,&rdfds)) 49 { 50 if(recv(i,buff,sizeof(buff),0)>0)//接收客户端数据 51 { 52 getpeername(i,(struct sockaddr*)&cltaddr,&addrlen); 53 printf("%s:%d-->%s\n",inet_ntoa(cltaddr.sin_addr),ntohs(cltaddr.sin_port),buff); 54 strcat(buff,"---echo"); 55 if(-1==send(i,buff,strlen(buff)+1,0))//回复客户端 56 error_exit("fail to send!"); 57 } 58 else//接收完毕后关闭各confd文件描述符/将文件描述符集合清空 59 { close(i); 60 FD_CLR(i,&tmpfds); 61 } 62 } 63 } 64 } 65 66 close(sockfd); 67 return 0; 68 }

浙公网安备 33010602011771号