Linux复用I/O-Select-server代码

来源:互联网 发布:新生入学调查问卷知乎 编辑:程序博客网 时间:2024/05/20 03:37

#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);

nfds: 监控的文件描述符集里最大文件描述符加1,因为此参数会告诉内核检测前多少个文件描述符的状态
readfds:监控有读数据到达文件描述符集合,传入传出参数
writefds:监控写数据到达文件描述符集合,传入传出参数
exceptfds:监控异常发生达文件描述符集合,如带外数据到达异常,传入传出参数
timeout:定时阻塞监控时间,3种情况:


1.NULL,永远等下去

2.设置timeval,等待固定时间

3.设置timeval里时间均为0,检查描述字后立即返回,轮询.

struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
void FD_CLR(int fd, fd_set *set);把文件描述符集合里fd0
int FD_ISSET(int fd, fd_set *set);测试文件描述符集合里fd是否置1
void FD_SET(int fd, fd_set *set);把文件描述符集合里fd位置1
void FD_ZERO(fd_set *set);把文件描述符集合里所有位清0

select的几大缺点:

(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

(3)select支持的文件描述符数量太小了,默认是1024


//============select-server代码==============

#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <ctype.h>#defineSELECT_MAX1024#definePORT8000#defineBUF1500#defineLISTEN128int main(void){struct sockaddr_in serveraddr,clientaddr;int serverfd,clientfd,maxfd,client_len,ready,flags,i;
int client[SELECT_MAX];//存放socket的数组fd_set set,allset;char buf[BUF];bzero(&serveraddr,sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port=htons(PORT);serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);serverfd = socket(AF_INET,SOCK_STREAM,0);bind(serverfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));listen(serverfd,LISTEN);FD_ZERO(&allset);FD_SET(serverfd,&allset);maxfd = serverfd;flags = -1;for(i = 0;i<SELECT_MAX;i++){client[i]=-1;//存放socket的数组}while(1){set = allset;ready = select(maxfd+1,&set,NULL,NULL,NULL);while(ready>0){if(FD_ISSET(serverfd,&set)){//有要联接的对象,将新的对象放入到Client[]数组中;//处理的是监听listensocket的消息client_len = sizeof(clientaddr);clientfd = accept(serverfd,(struct sockaddr*)&clientaddr,&client_len);for(i=0;i<SELECT_MAX;i++){if(client[i]==-1){client[i]=clientfd;FD_SET(clientfd,&allset);break;}}if(maxfd < clientfd)maxfd = clientfd;if(i == SELECT_MAX){printf("select监听序列已满\n");exit(0);}if(flags < i)flags = i;--ready;}else{//有数据要读取,遍历已连接Socket的数组,查看是否在fd_set中。//处理的是已连接的socket的信息。int tmpfd;int len,j;for(i = 0;i<=flags;i++){if(FD_ISSET(client[i],&set)){tmpfd = client[i];break;}}len = read(tmpfd ,buf,sizeof(buf));if(len == 0){close(tmpfd);client[i]=-1;FD_CLR(tmpfd,&allset);}else if(len < 0){perror("read");exit(0);}else{j = 0;while(j<len){buf[j] = toupper(buf[j]);j++;}write(tmpfd,buf,len);}--ready;}}}close(serverfd);return 0;}


原创粉丝点击