int select(int nfds, fd_set FAR* readfds, fd_set * writefds, fd_set * exceptfds, const struct timeval * timeout);
nfds: 是一个整数值, 是指集合中所有文件描述符 https://baike.baidu.com/item/文件描述符 的范围, 即所有文件描述符的最大值加 1. 在 Windows 中这个参数的值无所谓, 可以设置不正确.
readfds:(可选) 指针 https://baike.baidu.com/item/指针 , 指向一组等待可读性检查的套接口.
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); 用于测试指定的文件描述符是否在该集合中.
服务端代码:(客户端基本不变)
- #include "common.h"
- struct cli_t
- {
- int cfd;
- struct sockaddr_in caddr;
- struct cli_t *next;
- };
- typedef struct stu// 学生结构体
- {
- int id;
- char name[20];
- int score;
- struct stu *next;
- }Stu,*PStu;
- void fun(int sig)// 捕捉信号
- {
- printf("连接中断 \ n");
- return;
- }
- unsigned int ListLength(PStu ptr) // 计算链表长度
- {
- unsigned int l=0;
- while(ptr!=NULL)
- {
- l++;
- ptr=ptr->next;
- }
- return l;
- }
- PStu ListSort(PStu ptr) // 链表排序
- {
- PStu sorthead=NULL;
- unsigned int l=ListLength(ptr);
- while(l>0)
- {
- PStu p1=ptr;
- PStu p2=p1;
- int max=p1->score;
- while(p1!=NULL)
- {
- if(p1->score>max)
- {max=p1->score; p2=p1;}
- p1=p1->next;
- }
- PStu p3=ptr;
- if (p3==p2)
- ptr=p3->next;
- else
- { while(p3->next!=p2)
- p3=p3->next;
- p3->next=p2->next;
- }
- PStu r;
- p2->next=NULL;
- if(sorthead==NULL)
- sorthead=p2;
- else
- r->next=p2;
- r=p2;
- l--;
- }
- return sorthead;
- }
- void show(PStu head)// 打印链表函数
- {
- printf("学号 \ t 姓名 \ t 分数 \ n");
- while(head!=NULL)
- {
- printf("%d\t%s\t%d\n",head->id,head->name,head->score);
- head=head->next;
- }
- return ;
- }
- int read_file(int agv)// 接受信息 (子线程)
- {
- PStu head=NULL;
- Stu *ptr;
- PStu r;
- int nfd;
- int ret;
- nfd=(int)agv;// 接收传参 nfd
- signal(SIGPIPE,fun);
- printf("read...\n");
- while(1)
- {
- ptr=malloc(sizeof(Stu));
- ret=read(nfd,ptr,sizeof(Stu));
- if(ret<0)
- {
- perror("read");return -1;
- }
- if(ret==0)
- {
- head=ListSort(head);
- show(head);
- printf("read over\n");
- return 0;
- }
- if(ret>0);// 把链表读出来
- {
- ptr->next=NULL;
- if(head==NULL)
- {
- head=ptr;
- }
- else
- {
- r->next=ptr;
- }
- r=ptr;
- }
- }
- return 1;
- }
- int main()// 主线程, 一直工作, 接收客户端
- {
- PStu head=NULL;
- pthread_t pthid;
- int ret;
- int fd,nfd;
- struct sockaddr_in saddr,caddr;
- int addr_len;
- signal(SIGPIPE,fun);
- fd = socket(AF_INET,SOCK_STREAM,0);
- if(fd<0)
- {
- perror("socket");
- return -1;
- }
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(9000);
- inet_pton(AF_INET,"192.168.6.128",&saddr.sin_addr.s_addr);
- ret = bind(fd,(struct sockaddr*)&saddr,sizeof(saddr));
- if(ret<0)
- {
- perror("bind");
- goto END;
- }
- ret = listen(fd,20);
- if(ret<0)
- {
- perror("listen");
- goto END;
- }
- fd_set set,rset;// 创建文件描述符集合
- int *pfd;
- struct cli_t *chead=NULL;
- struct cli_t *pcli;
- int maxfd;
- FD_ZERO(&set);// 将文件描述符集清空
- FD_SET(fd,&set);// 在文件描述符集合中增加一个新的文件描述符
- maxfd=fd;
- while(1)// 循环接收多个客户端
- {
- rset=set;// 把 set 的文件描述符拷贝给 reset, 防止 set 发生改变
- printf("select...\n");
- ret=select(maxfd+1,&rset,NULL,NULL,NULL);// 对读进行操作等待 (无限等待)
- printf("select over && ret= %d\n",ret);
- if(ret<0)
- {
- perror("select");
- break;
- }
- if(FD_ISSET(fd,&rset))// 检查 fd 是否在文件描述符集中, select 将更新这个集合, 只保留符合条件的套节字在这个集合里面
- {
- // 接收连接
- addr_len = sizeof(caddr);
- printf("accept..\n");
- nfd = accept(fd,(struct sockaddr*)&caddr,&addr_len);
- if(nfd<0)
- {
- perror("accept");
- }
- printf("accept over..\n");
- // 加入集合
- FD_SET(nfd,&set);// 把 nfd 加入到 set 集合中
- if(nfd>maxfd)
- maxfd=nfd;
- // 加入链表
- pcli=malloc(sizeof(struct cli_t));
- pcli->cfd=nfd;
- pcli->caddr=caddr;
- pcli->next=chead;
- chead=pcli;
- }
- for(pcli=chead;pcli!=NULL;pcli=pcli->next)// 循环遍历, 哪个客户端准备好了 (写入并传输了数据就读出数据)
- {
- int tfd=pcli->cfd;
- if(!FD_ISSET(tfd,&rset))// 防止客户端没写入数据时阻塞在 read 里面
- continue;
- ret=read_file(tfd);
- if(ret<=0)
- {
- printf("read ret =0 tcp broken\n");
- FD_CLR(tfd,&set);// 客户端读取完毕且关闭, 清空集合
- }
- }printf("asd");
- }
- END:
- close(fd);
- return 0;
- }
来源: http://www.bubuko.com/infodetail-2677143.html