用select实现IO的复用-创新互联

select系统调用用于一次监控多个句柄(文件描述符)的状态变化的。程序会停在select处等待,直到被监视的句柄有一个或多个发生了状态改变。

创新互联公司长期为1000+客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为黑龙江企业提供专业的网站设计制作、成都网站建设,黑龙江网站改版等技术服务。拥有十多年丰富建站经验和众多成功案例,为您定制开发。

select函数原型:

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

nfds:表示文件描述符集的个数

readfds:当前有多少个读事件(有数据到了这个状态称之为读事件)

writefd:当前有多少个写事件(关心输出缓冲区是否已满)
最后一个结构体表示每个几秒钟醒来做其他事件,用来设置select等待时间

函数返回值:

执行成功返回描述符集当中状态已改变的个数

返回0表示在描述符状态改变前已经timeout

返回-1表示有错误发生,可能为某个套接字的带有外数据到达

关于select函数的相关函数操作

FD_CLR(inr fd,fd_set* set);来清除描述词组set中相关fd 的位

FD_ISSET(int fd,fd_set *set);判断该文件描述符是否在当前文件描述符集中

FD_SET(int fd,fd_set*set);将该描述符设置到当前文件描述符集中

FD_ZERO(fd_set *set);可以用来初始化文件描述符集

select模型中的fd_set,例:若fd_set为1字节,共有8位,则它的每一个位都可以对应一个文件描述符,若fd=1则应为0000 0001

将fd加入select监控集时,要用一个数组保存放到select监控集中的文件描述符,为了在select 返回后,该数组中保存的数据可以和fd_set进行FD_ISSET判断,select在返回后会把以前加入的但并无任何事件发生的fd清空,每次开始select前都要重新从数组取得fd

逐一加入。

使用select实现TCP通信

服务器端:

1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 #include
 10 int fileds[64]; //用一个数组保存select监控集中的文件描述符
 11 void Usage(const char* proc)
 12 {
 13     printf("Usage:%s [ip] [port]\n",proc);
 14 }
 15 
 16 int start(int port,char* ip)
 17 {
 18     int listen_sock=socket(AF_INET,SOCK_STREAM,0);
 19     if(listen_sock<0)
 20     {
 21         perror("socket");
 22         exit(1);
 23     }
  24     struct sockaddr_in local;
 25     local.sin_family=AF_INET;
 26     local.sin_port=htons(port);
 27     local.sin_addr.s_addr=inet_addr(ip);
 28     socklen_t len=sizeof(local);
 29     if(bind(listen_sock,(struct sockaddr*)&local,len)<0)
 30     {
 31         perror("bind");
 32         exit(2);
 33     }
 34     if(listen(listen_sock,5)<0)
 35     {
 36         perror("listen");
 37         exit(3);
 38     }
 39     return listen_sock;
 40 }
 41 int main(int argc,char* argv[])
 42 {
 43     if(argc!=3)
  44     {
 45         Usage(argv[0]);
 46         exit(1);
 47     }
 48     char* _ip=argv[1];
 49     int _port=atoi(argv[2]);
 50     int listen_sock=start(_port,_ip);//create socket
 51     int newsock=-1;
 52     int max_fd=0;
 53     fd_set _reads;//many of read event
 54     fd_set _writes;//many of write event
 55     struct sockaddr_in client;
 56     int fds_count=sizeof(fileds)/sizeof(fileds[0]);
 57     socklen_t len=sizeof(client);
 58     int i=0;
 59     while(i0)
 78             {
 79                 FD_SET(fileds[i],&_reads);
 80                 if(fileds[i]>max_fd)
 81                 {
 82                     max_fd=fileds[i];
 83                 }
 84             }
 85         }
 86         switch(select(max_fd+1,&_reads,NULL,NULL,&_timeout))
 87         {//the return val is how many fd is ready 
 88             case 0: //timeout
 89                 printf("select is timeout\n");
 90                 break;
 91             case -1://error
 92                 perror("select");
 93                 break;
 94             default:  //less than 1 fd is ready
 95             {
 96                 for(i=0;i0 &&FD_ISSET(fileds[i],&_reads))
122                     {
123                         char buf[1024];
124                         ssize_t _size=read(fileds[i],buf,sizeof(buf)-1);
124                         ssize_t _size=read(fileds[i],buf,sizeof(buf)-1);
125                         if(_size>0)
126                         {
127                             buf[_size]='\0';
128                             printf("client#%s",buf);
129                             write(fileds[i],buf,_size);
130                         }else if(_size==0)//client close
131                         {
132                             printf("client is closed...\n");
133                             close(fileds[i]);
134                             fileds[i]=-1;//set -1,
135                         }
136                     }
137                 }
138             }
139             break;
140    
141         }
142     }
143     return 0;
144 }

客户端:

1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 
  9 void Usage(const char*proc)
 10 {
 11     printf("Usage:%s [remoteip] [remoteport]\n",proc);
 12 }
 13 
 14 int main(int argc,char* argv[])
 15 {
 16     if(argc!=3)
 17      {
 18          Usage(argv[0]);
 19          exit(1);
 20      }
 21 
 22      int _port=atoi(argv[2]);
 23      char *_ip=argv[1];
 1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 
  9 void Usage(const char*proc)
 10 {
 11     printf("Usage:%s [remoteip] [remoteport]\n",proc);
 12 }
 13 
 14 int main(int argc,char* argv[])
 15 {
 16     if(argc!=3)
 17      {
 18          Usage(argv[0]);
 19          exit(1);
 20      }
 21 
 22      int _port=atoi(argv[2]);
 23      char *_ip=argv[1];
 24      int sock=socket(AF_INET,SOCK_STREAM,0);
 25      if(sock<0)
 26      {
 27          perror("socket");
 28          exit(2);
 29      }
 30      struct sockaddr_in remote;
 31      remote.sin_family=AF_INET;
 32      remote.sin_port=htons(_port);
 33      remote.sin_addr.s_addr=inet_addr(_ip);
 34      int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));
 35      if(ret<0)
 36      {
 37          perror("connect");
 38          exit(3);
 39      }
 40      char buf[1024];
 41      while(1)
 42      {
 43          memset(buf,'\0',sizeof(buf));
 44          printf("please input:");
 45          fflush(stdout);
 46          if(read(0,buf,sizeof(buf)-1)>0)
 47          {
 48              write(sock,buf,strlen(buf));
 49          }
 50    
 51          ssize_t _size=read(sock,buf,sizeof(buf)-1);
 52          if(_size>0)
 53          {
 54              printf("server----client:%s",buf);
 55          }
 56    
 57      }
 58      return 0;
 59 }

结果回显:

用select实现IO的复用

使用select实现多路复用同时也存在弊端:

每次调用select,都需要把fd集合从用户态拷贝到内核态,需要在内核中遍历传递进的所有文件描述符,当fd很多时导致开销大

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


名称栏目:用select实现IO的复用-创新互联
标题URL:http://ybzwz.com/article/dcsoej.html