I/O多路复用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include"pack.h" 2 3 /****************************************************/ 4 //用户保存caddr的链表 5 void add_node_caddr(int confd,struct sockaddr_in caddr) 6 { 7 struct online_c *temp=(struct online_c *)malloc(sizeof(struct online_c)) 8 ; 9 temp->confd=confd; 10 temp->caddr=caddr; 11 temp->next=c_head; 12 c_head=temp; 13 } 14 15 void delete_C_node(int confd) 16 { 17 if(c_head==NULL) 18 return ; 19 struct online_c * p=NULL; 20 if(c_head->confd==confd && c_head->next==NULL) 21 { 22 free(c_head); 23 c_head=NULL; 24 return ; 25 } 26 else if(c_head->confd==confd && c_head->next!=NULL) 27 { 28 p=c_head->next; 29 free(c_head); 30 c_head=p; 31 return ; 32 } 33 p=c_head; 34 35 struct online_c * q=NULL; 36 while(p->next!=NULL) 37 { 38 if(p->next->confd==confd) 39 { 40 q=p->next; 41 p->next=q->next; 42 free(q); 43 return ; 44 } 45 p=p->next; 46 } 47 printf("该节点不存在\n"); 48 return ; 49 } 50 51 struct sockaddr_in search_caddr(int confd) 52 { 53 struct online_c * p=c_head; 54 while(p!=NULL) 55 { 56 if(p->confd==confd) 57 return p->caddr; 58 p=p->next; 59 } 60 } 61 62 /***********************用于保存在线用户的链表********* 63 *********************/ 64 void add_node(int confd,int id) 65 { 66 Pmen temp=(Pmen)malloc(sizeof(Men)); 67 temp->data.id=id; 68 temp->data.confd=confd; 69 70 71 temp->data.caddr=search_caddr(confd); 72 73 delete_C_node(confd); 74 temp->next=head; 75 head=temp; 76 return ; 77 } 78 79 void show_link() 80 { 81 Pmen p=head; 82 printf("id\tconfd\tport\taddr\n"); 83 char addr[20]; 84 while(p!=NULL) 85 { 86 printf("%d\t%d\t%d\t%s\n",p->data.id,p->data.confd,\ 87 ntohs(p->data.caddr.sin_port),\ 88 inet_ntop(AF_INET,&(p->data.caddr.sin_addr.s_addr) 89 ,addr,sizeof(addr))); 90 p=p->next; 91 } 92 } 93 94 void delete_node(int confd) 95 { 96 Pmen p=NULL; 97 if(head->data.confd==confd && head->next==NULL) 98 { 99 free(head); 100 head=NULL; 101 return ; 102 } 103 else if(head->data.confd==confd && head->next!=NULL) 104 { 105 { 106 p=head->next; 107 free(head); 108 head=p; 109 return ; 110 } 111 p=head; 112 113 Pmen q=NULL; 114 while(p->next!=NULL) 115 { 116 if(p->next->data.confd==confd) 117 { 118 q=p->next; 119 p->next=q->next; 120 free(q); 121 return ; 122 } 123 p=p->next; 124 } 125 printf("该节点不存在\n"); 126 return ; 127 } 128 129 int search_confd(int id) 130 { 131 Pmen p=head; 132 while(p!=NULL) 133 { 134 if(p->data.id==id) 135 return p->data.confd; 136 p=p->next; 137 } 138 return -1; 139 } 140 141 int search_id(int confd) 142 { 143 Pmen p=head; 144 while(p!=NULL) 145 { 146 if(p->data.confd==confd) 147 return p->data.id; 148 p=p->next; 149 } 150 return -1; 151 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifndef __PACK_H_ 2 #define __PACK_H_ 3 #include<sys/socket.h> 4 #include<sys/types.h> 5 #include<stdio.h> 6 #include<netinet/in.h> 7 #include<arpa/inet.h> 8 #include<errno.h> 9 #include<string.h> 10 #include<stdlib.h> 11 #include<unistd.h> 12 #include <sys/time.h> 13 #include <sys/types.h> 14 #include <unistd.h> 15 16 struct pack//用户封包 17 { 18 int type; 19 int len; 20 char buf[0]; 21 }; 22 23 struct DATA //用登录和注册 24 { 25 int confd; 26 int flag; 27 int id; 28 char name[20]; 29 char passwd[20]; 30 struct sockaddr_in caddr; 31 }; 32 typedef struct online//用户在线用户链表 33 { 34 struct DATA data; 35 struct online *next; 36 }Men,*Pmen; 37 38 struct message//用于发送信息 39 { 40 int id;//who your want to send 41 char buf[20];//message 42 }; 43 44 struct online_c//用户保存链接了但是没登录的客户端的caddr 45 { 46 int confd; 47 struct sockaddr_in caddr; 48 struct online_c *next; 49 }; 50 void myunpack(int confd,struct pack temp); 51 void login(int confd); 52 void person_register(int confd); 53 void send_message(int confd,int len); 54 55 void add_node(int confd,int id); 56 void delete_node(int confd); 57 58 int search_confd(int id); 59 int search_id(int ); 60 61 void show_link(); 62 struct online * head; 63 64 struct online_c *c_head; 65 void add_node_caddr(int confd,struct sockaddr_in caddr); 66 void delete_C_node(int confd); 67 struct sockaddr_in search_caddr(int confd); 68 69 #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include"pack.h" 2 #include<mysql/mysql.h> 3 4 void send_message(int confd,int len) 5 { 6 printf("on send message\n"); 7 struct message temp; 8 int ret=read(confd,&temp,sizeof(temp)); 9 10 int sendfd=search_confd(temp.id); 11 printf("sendfd=%d id=%d\n",sendfd,temp.id); 12 if(sendfd==-1) 13 return ; 14 int id=search_id(confd); 15 temp.id=id; 16 17 write(sendfd,&temp,sizeof(temp)); 18 printf("ret=%d %s\n",ret,temp.buf); 19 return ; 20 } 21 22 23 void myunpack(int confd,struct pack temp) 24 { 25 26 switch(temp.type) 27 { 28 case 1: 29 login(confd); 30 break; 31 case 2: person_register(confd); 32 break; 33 case 3: 34 send_message(confd,temp.len); 35 break; 36 default: 37 printf("%s default\n",__func__); 38 return ; 39 } 40 } 41 42 void login(int confd) 43 { 44 struct DATA temp; 45 int ret=read(confd,&temp,sizeof(struct DATA));//读取登录信息 46 if(ret<=0) 47 { 48 printf("read login pack error\n"); 49 close(confd); 50 return ; 51 } 52 MYSQL *conn; 53 conn=mysql_init(NULL); 54 if(!mysql_real_connect(conn,"localhost","root","513920","membe 55 r",0,NULL,0)) 56 { 57 printf("connect mysql error\n"); 58 temp.flag=-1; 59 write(confd,&temp,sizeof(temp)); 60 return ; 61 } 62 char buf[100]; 63 sprintf(buf,"select * from person where id=%d and passwd=\'%s\'",temp.id,temp.passwd); 64 printf("%s\n",buf); 65 if(mysql_query(conn,buf)) 66 { 67 printf("mysql_query error\n"); 68 temp.flag=-1; 69 write(confd,&temp,sizeof(temp)); 70 return ; 71 } 72 MYSQL_RES *res; 73 MYSQL_ROW row; 74 75 res=mysql_use_result(conn); 76 row=mysql_fetch_row(res); 77 if(row==NULL) 78 { 79 temp.flag=-1; 80 printf("the person is not exist\n"); 81 write(confd,&temp,sizeof(temp)); 82 return; 83 } 84 85 temp.flag=1; 86 strcpy(temp.name,row[1]); 87 88 mysql_free_result(res); 89 mysql_close(conn); 90 91 write(confd,&temp,sizeof(temp)); 92 add_node(confd,temp.id); 93 printf("登录成功\n"); 94 return ; 95 } 96 97 void person_register(int confd) 98 { 99 struct DATA temp; 100 int ret=read(confd,&temp,sizeof(struct DATA));//读取登录信息 101 if(ret<=0) 102 { 103 printf("read login pack error\n"); 104 close(confd); 105 return ; 106 } 107 MYSQL *conn; 108 conn=mysql_init(NULL); 109 if(!mysql_real_connect(conn,"localhost","root","513920","membe 110 r",0,NULL,0)) 111 { 112 printf("connect mysql error\n"); 113 temp.flag=-1; 114 write(confd,&temp,sizeof(temp)); 115 return ; 116 } 117 char buf[100]; 118 sprintf(buf,"insert into person(name,passwd) values(\'%s\',\' 119 %s\')",temp.name,temp.passwd); 120 if(mysql_query(conn,buf)) 121 { 122 printf("mysql_query error\n"); 123 temp.flag=-1; 124 write(confd,&temp,sizeof(temp)); 125 return ; 126 } 127 128 if(mysql_query(conn,"select max(id) as value from person")) 129 { 130 printf("mysql_query select id error\n"); 131 temp.flag=-1; 132 write(confd,&temp,sizeof(temp)); 133 return ; 134 135 } 136 137 MYSQL_RES *res; 138 MYSQL_ROW row; 139 140 res=mysql_use_result(conn); 141 row=mysql_fetch_row(res); 142 if(row==NULL) 143 { 144 temp.flag=-1; 145 printf("the person is not exist\n"); 146 write(confd,&temp,sizeof(temp)); 147 return ; 148 } 149 150 temp.flag=1; 151 temp.id=atoi(row[0]); 152 153 mysql_free_result(res); 154 mysql_close(conn); 155 write(confd,&temp,sizeof(temp)); 156 add_node(confd,temp.id); 157 printf("注册成功\n"); 158 159 return ; 160 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #ifndef __CPACK_H_ 2 #define __CPACK_H_ 3 #include<sys/socket.h> 4 #include<sys/types.h> 5 #include<stdio.h> 6 #include<netinet/in.h> 7 #include<arpa/inet.h> 8 #include<errno.h> 9 #include<string.h> 10 #include<stdlib.h> 11 #include<unistd.h> 12 #include <sys/time.h> 13 #include <sys/types.h> 14 #include <unistd.h> 15 16 struct pack 17 { 18 int type; 19 int len; 20 char buf[0]; 21 }; 22 23 struct DATA 24 { 25 int confd; 26 int flag; 27 int id; 28 char name[20]; 29 char passwd[20]; 30 struct sockaddr_in caddr; 31 }; 32 struct online 33 { 34 struct DATA data; 35 struct online *next; 36 }; 37 38 struct message 39 { 40 int id;//who your want to send 41 char buf[20];//message 42 }; 43 44 struct pack * mypack(int type,int len,void * buf); 45 46 void menu(int sockfd); 47 void login(int sockfd); 48 void person_register(int sockfd); 49 50 void send_message(int sockfd); 51 void recv_message(int sockfd); 52 53 #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include"cpack.h" 2 struct pack * mypack(int type,int len,void * buf) 3 { 4 struct pack * temp=(struct pack *)malloc(sizeof(struct pack)+l 5 en); 6 temp->type=type; 7 temp->len=len; 8 memcpy(temp->buf,buf,len); 9 return temp; 10 } 11 void menu(int sockfd) 12 { 13 system("clear"); 14 printf("*******************\n"); 15 printf("* 0 exit *\n"); 16 printf("* 1 login *\n"); 17 printf("* 2 register *\n"); 18 printf("*******************\n"); 19 int key; 20 printf("please input your chioce:"); 21 scanf("%d",&key); 22 23 switch(key) 24 { 25 case 1: 26 login(sockfd); 27 break; 28 case 2: person_register(sockfd); 29 break; 30 case 0: 31 exit(0); 32 break; 33 default: 34 printf("error input\n"); 35 } 36 } 37 38 void login(int sockfd) 39 { 40 struct DATA temp; 41 printf("请输入id:"); 42 scanf("%d",&temp.id); 43 printf("请输入passwd:"); 44 scanf("%s",temp.passwd); 45 46 struct pack *p=mypack(1,sizeof(temp),&temp); 47 int ret=write(sockfd,p,sizeof(struct pack)+sizeof(temp));//将登录信息写给服务器 48 if(ret<=0) 49 { 50 printf("write error\n"); 51 close(sockfd); 52 exit(0); 53 } 54 ret=read(sockfd,&temp,sizeof(temp)); 55 if(ret<=0 || ret!=sizeof(temp)) 56 { 57 printf("read login pack error\n"); 58 close(sockfd); 59 exit(0); 60 } 61 if(temp.flag!=1) 62 { 63 printf("用户名或者密码错误\n"); 64 close(sockfd); 65 exit(0); 66 } 67 printf("欢迎%s登录\n",temp.name); 68 } 69 70 void person_register(int sockfd) 71 { 72 struct DATA temp; 73 printf("请输入name:"); 74 scanf("%s",temp.name); 75 printf("请输入passwd:"); 76 scanf("%s",temp.passwd); 77 78 struct pack *p=mypack(2,sizeof(temp),&temp); 79 int ret=write(sockfd,p,sizeof(temp)+sizeof(struct pack));//将登录信息写给服务器 80 free(p); 81 if(ret<=0) 82 { 83 printf("write error\n"); 84 close(sockfd); 85 exit(0); 86 } 87 ret=read(sockfd,&temp,sizeof(temp)); 88 if(ret<=0 || ret!=sizeof(temp)) 89 { 90 printf("read login pack error\n"); 91 close(sockfd); 92 exit(0); 93 } 94 if(temp.flag!=1) 95 { 96 printf("注册失败\n"); 97 close(sockfd); 98 exit(0); 99 } 100 printf("注册成功 id----%d\n",temp.id); 101 } 102 103 void send_message(int sockfd) 104 { 105 struct message mes; 106 printf("请输入你要发送信息(1001-yisheng):"); 107 scanf("%d-%s",&mes.id,mes.buf); 108 109 struct pack * temp=mypack(3,sizeof(mes),&mes); 110 write(sockfd,temp,sizeof(struct pack)+sizeof(mes)); 111 free(temp); 112 } 113 void recv_message(int sockfd) 114 { 115 struct message temp; 116 read(sockfd,&temp,sizeof(temp)); 117 printf("recv from %d message:%s\n",temp.id,temp.buf); 118 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include"pack.h" 2 int main(int argc,char ** argv) 3 { 4 head=NULL; 5 c_head=NULL; 6 int listenfd; 7 8 listenfd=socket(AF_INET,SOCK_STREAM,0); 9 struct sockaddr_in myaddr; 10 myaddr.sin_family=AF_INET; 11 myaddr.sin_port=htons(atoi(argv[1])); 12 inet_pton(AF_INET,"192.168.6.11",&myaddr.sin_addr.s_addr); 13 14 int ret=bind(listenfd,(struct sockaddr *)&myaddr,sizeof(myaddr 15 )); 16 if(ret<0) 17 { 18 perror("bind failed:"); 19 exit(0); 20 } 21 ret=listen(listenfd,20); 22 if(ret<0) 23 { 24 perror("listen failed:"); 25 exit(0); 26 } 27 struct sockaddr_in caddr; 28 int len=sizeof(caddr); 29 int confd; 30 struct pack temp; 31 32 fd_set set,rset;//定义一个文件描述符集合 33 FD_ZERO(&set);//清空文件描述符集合 34 FD_SET(listenfd,&set);//将文件描述符添加到集合里面去 35 36 int maxfd=listenfd; 37 /* 38 int select(int nfds, fd_set *readfds, fd_set *writefds, 39 fd_set *exceptfds, struct timeval *timeout); 40 41 第一个参数:是你要监听的最大文件描述符+1 42 返回值:如果有事件产生,返回的事件的个数.如果返回值为0,表示超时等待,出错返回负数 43 44 */ 45 int nfound; 46 47 while(1) 48 { 49 rset=set; 50 nfound=select(maxfd+1,&rset,NULL,NULL,NULL); 51 printf("nfound=%d\n",nfound); 52 if(nfound<0) 53 { 54 perror("select error"); 55 continue; 56 } 57 else if(nfound==0) 58 { 59 printf("超时等待..\n"); 60 continue; 61 } 62 if(FD_ISSET(listenfd,&rset))//FD_ISSET 判断文件描述符是否有事件产生,有返回真,没有返回假 63 { 64 printf("accept\n"); 65 confd=accept(listenfd,(struct sockaddr*)&caddr,&len); 66 if(confd<0) 67 { 68 perror("accept failed:"); 69 continue; 70 } 71 FD_SET(confd,&set); 72 if(confd>maxfd) 73 maxfd=confd; 74 FD_CLR(listenfd,&rset);//将监听的文件描述符集合中移除. 75 76 add_node_caddr(confd,caddr); 77 } 78 for(int fd=0;fd<=maxfd;fd++) 79 { 80 if(fd==listenfd) 81 continue; 82 if(!FD_ISSET(fd,&rset)) 83 continue; 84 ret=read(fd,&temp,sizeof(temp)); 85 if(ret<0) 86 { 87 FD_CLR(fd,&set);//将监听的文件描述符集合中移除. 88 close(fd); 89 FD_CLR(fd,&set);//将监听的文件描述符集合中移除. 90 delete_node(fd); 91 perror("read failed:"); 92 continue; 93 } 94 else if(ret==0) 95 { 96 printf("client closed\n"); 97 FD_CLR(fd,&set);//将监听的文件描述符集合中移除. 98 delete_node(fd); 99 close(fd); 100 continue; 101 } 102 else 103 { 104 printf("temp.type=%d\n",temp.type); 105 myunpack(fd,temp); 106 } 107 } 108 show_link(); 109 } 110 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<sys/socket.h> 2 #include<sys/types.h> 3 #include<stdio.h> 4 #include<netinet/in.h> 5 #include<arpa/inet.h> 6 #include<errno.h> 7 #include<string.h> 8 #include<stdlib.h> 9 #include<unistd.h> 10 #include"cpack.h" 11 int main(int argc,char ** argv) 12 { 13 //int socket(int domain, int type, int protocol); 14 int sockfd; 15 sockfd=socket(AF_INET,SOCK_STREAM,0); 16 printf("sockfd=%d\n",sockfd); 17 18 /* 19 int connect(int sockfd, struct sockaddr *serv_addr, int addrlen ); 20 作用:向服务器请求三次握手 21 参数1:套接字 22 参数2:服务端的地址族结构,也就是地址类型,IP,端口 23 参数3:服务端地址族的大小 24 返回值:成功则返回非负数 25 */ 26 struct sockaddr_in seraddr; 27 seraddr.sin_family=AF_INET; 28 seraddr.sin_port=htons(atoi(argv[1])); 29 inet_pton(AF_INET,"192.168.6.11",&seraddr.sin_addr.s_addr); 30 31 int ret=connect(sockfd,(struct sockaddr *)&seraddr,sizeof(seraddr)); 32 if(ret<0) 33 { 34 perror("connect failed:"); 35 exit(0); 36 } 37 38 // char buf[20]; 39 //scanf("%s",buf); 40 // write(sockfd,buf,strlen(buf)+1); 41 menu(sockfd); 42 43 pid_t pid; 44 pid=fork(); 45 if(pid==0) 46 { 47 while(1) 48 { 49 send_message(sockfd); 50 } 51 } 52 else if(pid>0) 53 { 54 while(1) 55 { 56 recv_message(sockfd); 57 } 58 } 59 close(sockfd); 60 61 return 0; 62 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 ALL: 2 gcc client.c cpack.c -o client 3 gcc server.c pack.c link.c -o server -lmysqlclient 4 clean: 5 rm -rf client server
make后运行./server 7319 ./client 7319 效果如下: