网络编程——I/O复用
Posted it8343
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程——I/O复用相关的知识,希望对你有一定的参考价值。
int select( int nfds, fd_set FAR* readfds, fd_set * writefds, fd_set * exceptfds, const struct timeval * timeout);
nfds:是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1。在Windows中这个参数的值无所谓,可以设置不正确。
readfds:(可选)指针,指向一组等待可读性检查的套接口。
writefds:(可选)指针,指向一组等待可写性检查的套接口。
exceptfds:(可选)指针,指向一组等待错误检查的套接口。
timeout:select()最多等待时间,对阻塞操作则为NULL。
如果对readfds、writefds或exceptfds中任一个组类不感兴趣,可将它置为空NULL。
在socket.h头文件中共定义了四个宏来操作描述字集。
FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
服务端代码:(客户端基本不变)
1 #include "common.h" 2 3 struct cli_t 4 { 5 int cfd; 6 struct sockaddr_in caddr; 7 struct cli_t *next; 8 }; 9 10 typedef struct stu//学生结构体 11 { 12 int id; 13 char name[20]; 14 int score; 15 struct stu *next; 16 }Stu,*PStu; 17 18 void fun(int sig)//捕捉信号 19 { 20 printf("连接中断 "); 21 return; 22 } 23 24 unsigned int ListLength(PStu ptr) //计算链表长度 25 { 26 unsigned int l=0; 27 while(ptr!=NULL) 28 { 29 l++; 30 ptr=ptr->next; 31 } 32 return l; 33 } 34 35 PStu ListSort(PStu ptr) //链表排序 36 { 37 PStu sorthead=NULL; 38 unsigned int l=ListLength(ptr); 39 while(l>0) 40 { 41 PStu p1=ptr; 42 PStu p2=p1; 43 int max=p1->score; 44 while(p1!=NULL) 45 { 46 if(p1->score>max) 47 {max=p1->score; p2=p1;} 48 p1=p1->next; 49 } 50 PStu p3=ptr; 51 if (p3==p2) 52 ptr=p3->next; 53 else 54 { while(p3->next!=p2) 55 p3=p3->next; 56 57 p3->next=p2->next; 58 } 59 60 PStu r; 61 p2->next=NULL; 62 if(sorthead==NULL) 63 sorthead=p2; 64 else 65 r->next=p2; 66 67 r=p2; 68 l--; 69 } 70 return sorthead; 71 } 72 73 void show(PStu head)//打印链表函数 74 { 75 printf("学号 姓名 分数 "); 76 while(head!=NULL) 77 { 78 printf("%d %s %d ",head->id,head->name,head->score); 79 head=head->next; 80 } 81 return ; 82 } 83 84 int read_file(int agv)//接受信息(子线程) 85 { 86 PStu head=NULL; 87 Stu *ptr; 88 PStu r; 89 int nfd; 90 int ret; 91 nfd=(int)agv;//接收传参nfd 92 93 signal(SIGPIPE,fun); 94 printf("read... "); 95 while(1) 96 { 97 ptr=malloc(sizeof(Stu)); 98 ret=read(nfd,ptr,sizeof(Stu)); 99 if(ret<0) 100 { 101 perror("read");return -1; 102 } 103 if(ret==0) 104 { 105 head=ListSort(head); 106 show(head); 107 printf("read over "); 108 return 0; 109 } 110 if(ret>0);//把链表读出来 111 { 112 ptr->next=NULL; 113 if(head==NULL) 114 { 115 head=ptr; 116 } 117 else 118 { 119 r->next=ptr; 120 } 121 r=ptr; 122 } 123 } 124 return 1; 125 } 126 127 int main()//主线程,一直工作,接收客户端 128 { 129 PStu head=NULL; 130 pthread_t pthid; 131 int ret; 132 int fd,nfd; 133 struct sockaddr_in saddr,caddr; 134 int addr_len; 135 signal(SIGPIPE,fun); 136 fd = socket(AF_INET,SOCK_STREAM,0); 137 if(fd<0) 138 { 139 perror("socket"); 140 return -1; 141 } 142 saddr.sin_family = AF_INET; 143 saddr.sin_port = htons(9000); 144 inet_pton(AF_INET,"192.168.6.128",&saddr.sin_addr.s_addr); 145 ret = bind(fd,(struct sockaddr*)&saddr,sizeof(saddr)); 146 if(ret<0) 147 { 148 perror("bind"); 149 goto END; 150 } 151 ret = listen(fd,20); 152 if(ret<0) 153 { 154 perror("listen"); 155 goto END; 156 } 157 158 fd_set set,rset;//创建文件描述符集合 159 int *pfd; 160 struct cli_t *chead=NULL; 161 struct cli_t *pcli; 162 int maxfd; 163 164 FD_ZERO(&set);//将文件描述符集清空 165 FD_SET(fd,&set);//在文件描述符集合中增加一个新的文件描述符 166 maxfd=fd; 167 168 while(1)//循环接收多个客户端 169 { 170 rset=set;//把set的文件描述符拷贝给reset,防止set发生改变 171 printf("select... "); 172 ret=select(maxfd+1,&rset,NULL,NULL,NULL);//对读进行操作等待(无限等待) 173 printf("select over && ret= %d ",ret); 174 175 if(ret<0) 176 { 177 perror("select"); 178 break; 179 } 180 if(FD_ISSET(fd,&rset))//检查fd是否在文件描述符集中, select将更新这个集合,只保留符合条件的套节字在这个集合里面 181 { 182 //接收连接 183 addr_len = sizeof(caddr); 184 printf("accept.. "); 185 nfd = accept(fd,(struct sockaddr*)&caddr,&addr_len); 186 if(nfd<0) 187 { 188 perror("accept"); 189 } 190 printf("accept over.. "); 191 //加入集合 192 FD_SET(nfd,&set);//把nfd加入到set集合中 193 if(nfd>maxfd) 194 maxfd=nfd; 195 196 // 加入链表 197 pcli=malloc(sizeof(struct cli_t)); 198 pcli->cfd=nfd; 199 pcli->caddr=caddr; 200 pcli->next=chead; 201 chead=pcli; 202 } 203 for(pcli=chead;pcli!=NULL;pcli=pcli->next)//循环遍历,哪个客户端准备好了(写入并传输了数据就读出数据) 204 { 205 int tfd=pcli->cfd; 206 if(!FD_ISSET(tfd,&rset))//防止客户端没写入数据时阻塞在read里面 207 continue; 208 ret=read_file(tfd); 209 if(ret<=0) 210 { 211 printf("read ret =0 tcp broken "); 212 FD_CLR(tfd,&set);//客户端读取完毕且关闭,清空集合 213 } 214 }printf("asd"); 215 } 216 END: 217 close(fd); 218 return 0; 219 }
以上是关于网络编程——I/O复用的主要内容,如果未能解决你的问题,请参考以下文章