> 文章列表 > IO多路复用的三种实现:select

IO多路复用的三种实现:select

IO多路复用的三种实现:select

select

 int select(int nfds, fd_set * readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

功能:多路IO复用。

参数:

 nfds: readfsd\\ writefds\\exceptfds三个位图中使用的最大的文件描述符号+1.

 readfds: 位图(128Byte,1024bit),需要监听的读事件集合

 writefds: 位图(128Byte,1024bit),需要监听的写事件集合

exceptfds: 位图(128Byte,1024bit),需要监听的异常事件集合

 timeout:超时时长,传NULL:如果没有监听的事件没有发生,就一直阻塞等待;传非0:表示超时时间,在规定的时间内如果监听的时间都没有发生,select 返回0;传0:表示非阻塞。调用的时候查看一遍监听集合,如果没有任何事件发生,select立即返回0。

返回值:

-1,出错并设置errno;0:表示没有任何监听的事发生;>0:监听的三个集合发生的事件和。

优点:

跨平台,开销小。

缺点:

受限数据结构的限制,能够监听的文件描述符上限1024个。

轮询监听机制,在活跃用户量小的时候监听效率比较低。

大量的用户和内核空间的数据拷贝。

利用select单进程实现多可客户端连接的服务器代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>                                                              
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<sys/wait.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<fcntl.h>
#include<arpa/inet.h>
#include<sys/select.h>
#define SERPORT 8000
#define SERIP "IP地址"int main(int argc, char* argv[])
{int lfd = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in seraddr,cliaddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(SERPORT);int dst;inet_pton(AF_INET,SERIP,(void*)&dst);seraddr.sin_addr.s_addr = dst;int ret = bind(lfd,(struct sockaddr*)&seraddr,sizeof(seraddr));listen(lfd,64);socklen_t addrlen = sizeof(cliaddr);char buf[1024];int maxfd;fd_set rset, aset;FD_ZERO(&aset);FD_SET(lfd,&aset);maxfd = lfd;int i = 0;int cfd;char clip[32];while(1){rset = aset;int sret = select(maxfd + 1, &rset, NULL, NULL, NULL);if(sret<0){perror("select error");exit(1);}if(FD_ISSET(lfd, &rset)){cfd = accept(lfd,(struct sockaddr*)&cliaddr,&addrlen);if(cfd<0){perror("accept error");exit(1);}//网络字节序整形IP地址转化成一个本地字节序点分十进制的字符窜IPinet_ntop(AF_INET,&cliaddr.sin_addr,clip,sizeof(clip));printf("clien IP=%s,PORT=%d connect ok\\n",clip,ntohs(cliaddr.sin_port));FD_SET(cfd, &aset);if(cfd>maxfd){maxfd = cfd;}if(--sret ==0 ){continue;}}for(i = lfd+1;i<maxfd+1;i++){if(FD_ISSET(i, &rset)){int rr = read(i,buf,sizeof(buf));if(rr < 0){perror("read error");exit(1);}else if(rr == 0){//客户端断开连接FD_CLR(i, &aset);close(i);printf("客户端断开连接\\n");}write(STDOUT_FILENO,buf,rr);write(i,buf,rr);if(--sret == 0){break;}}}}   return 0;
}