网络编程——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);用于测试指定的文件描述符是否在该集合中。
 
 
服务端代码:(客户端基本不变)
  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("连接中断\n");
 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("学号\t姓名\t分数\n");
 76     while(head!=NULL)
 77     {
 78         printf("%d\t%s\t%d\n",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...\n");
 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\n");
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...\n");
172         ret=select(maxfd+1,&rset,NULL,NULL,NULL);//对读进行操作等待(无限等待)
173         printf("select over && ret= %d\n",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..\n");
185             nfd = accept(fd,(struct sockaddr*)&caddr,&addr_len);
186             if(nfd<0)
187             {
188                 perror("accept");
189             }
190             printf("accept over..\n");
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\n");
212                 FD_CLR(tfd,&set);//客户端读取完毕且关闭,清空集合
213             }
214         }printf("asd");
215     }
216 END:
217     close(fd);
218     return 0;
219 }

猜你喜欢

转载自www.cnblogs.com/it8343/p/9280642.html