Linux下IO复用用并发服务器模型

2911阅读 0评论2011-05-06 0xC1988
分类:LINUX

IO复用意味着如果一个或多个I/O条件满足我们就能被通知到,这种能力就叫IO复用。利用select函数,可以实现IO复用的功能。select函数的定义如下:
  1. int select (int maxfdp+1, fd_set *readset,fds_set *writeset,fd_set *execepset,const struct timeval * timeout);

函数的返回值是准备好描述字的正数目,0为超时,-1为出错。

参数maxfd+1指定被测试的描述字个数,它是被测试描述字最大值加1.

参数readset,writeset,execepset指定让内核测试的读、写、异常条件的描述字,如果不需要用到,则将其设为NULL。

select函数使用描述字符集为参数readset(writeset或者execepset)指定多个描述字,使用以下几个宏操作

 

  1. void FD_ZERO(fd_set *fdset) /*将所有位置为0*/

  2. void FD_SET(int fd,fd_set *fdset) /*将fd位置为1*/

  3. void FD_CLR(int fd,fd_set *fdset) /*将fd位置为0*/

  4. int FD_ISSET(int fd,fd_set *fdset) /*检测fa位是否置为1*/

timeout是一个timeval结构,这个结构用三种可能:

1、为空指针,select永远等待下去

2、等待固定时间:在不超过timeout指定时间内有描述字准备好I/O返回

3、根本不等待:检查描述字后立即返回

 

这个模型服务器端功能还是将客户端发过来的字符串中的小写字母全部转化为大学字母后发回客户端。客户端采用 linux多进程并发服务模型 中客户端的程序。代码如下:

 

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/time.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <sys/select.h>


  11. #define PORT 1111
  12. #define BACKLOG 5

  13. typedef struct{
  14.     int fd;
  15.     struct sockaddr_in addr;
  16. }clientinfo;

  17. int process(clientinfo * client)
  18. {
  19.     char buf[1024];
  20.     int n=0;
  21.     if(0<(n=read(client->fd,buf,sizeof(buf)))){
  22.         int i=0;
  23.         buf[n]='\0';
  24.         printf("got a message <%s> from %s\n",buf,inet_ntoa(client->addr.sin_addr));
  25.         while(buf[i]!='\0'&&i<1024){
  26.             if(buf[i]>='a'&&buf[i]<='z')
  27.                 buf[i]+=('A'-'a');
  28.             i++;
  29.         }
  30.         write(client->fd,buf,strlen(buf));
  31.     }
  32.     return n;
  33. }

  34. int main(){
  35.     int listenfd,connectfd;
  36.     int nready;
  37.     fd_set rset,allset;
  38.     struct sockaddr_in server;
  39.     clientinfo client[FD_SETSIZE];

  40.     if(-1==(listenfd=socket(AF_INET,SOCK_STREAM,0))){
  41.         perror("create socket error\n");
  42.         exit(1);
  43.     }

  44.     int opt=SO_REUSEADDR;
  45.     setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

  46.     bzero(&server,sizeof(struct sockaddr_in));
  47.     server.sin_family=AF_INET;
  48.     server.sin_port=htons(PORT);
  49.     server.sin_addr.s_addr=htonl(INADDR_ANY);

  50.     if(-1==(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr )))){
  51.         perror("bind error\n");
  52.         exit(1);
  53.     }

  54.     if(-1==(listen(listenfd,BACKLOG))){
  55.         perror("listen error\n");
  56.         exit(1);
  57.     }

  58.     int maxfd=listenfd;
  59.     int maxi=-1;
  60.     
  61.     int i;
  62.     for(i=0;i<FD_SETSIZE;i++)
  63.         client[i].fd=maxi;

  64.     FD_ZERO(&allset);
  65.     FD_SET(listenfd,&allset);

  66.     struct sockaddr_in client_addr;
  67.     int len=sizeof(client_addr);

  68.     while(1){
  69.         printf("waiting...\n");
  70.         rset=allset;
  71.         nready=select(maxfd+1,&rset,NULL,NULL,NULL);

  72.         printf("nready= %d\n",nready);
  73.         if(FD_ISSET(listenfd,&rset)){

  74.             if(-1==(connectfd=accept(listenfd,(struct sockaddr *)&client_addr,&len))){
  75.                 perror("accept error\n");
  76.                 continue;
  77.             }
  78.             
  79.             printf("get a connection from %s\n",inet_ntoa(client_addr.sin_addr));

  80.             for(i=0;i<FD_SETSIZE;i++)
  81.                 if(client[i].fd<0){
  82.                     client[i].fd=connectfd;
  83.                     client[i].addr=client_addr;
  84.                     break;
  85.                 }
  86.             if(FD_SETSIZE == i)
  87.                 printf("too many clients\n");
  88.             FD_SET(connectfd,&allset);

  89.             if(connectfd>maxfd)
  90.                 maxfd=connectfd;
  91.             if(i>maxi)
  92.                 maxi=i;
  93.             if(--nready<=0)
  94.                 continue;
  95.         }

  96.         for(i=0;i<=maxi;i++){
  97.             if(client[i].fd<0)
  98.                 continue;
  99.             if(FD_ISSET(client[i].fd,&rset)){
  100.                 if(process(&client[i])<=0){
  101.                     printf("client( %s ) closed connection\n",inet_ntoa(client[i].addr.sin_addr));
  102.                     close(client[i].fd);
  103.                     FD_CLR(client[i].fd,&allset);
  104.                     client[i].fd=-1;

  105.                 }
  106.                 if(--nready<=0)
  107.                     break;
  108.             }
  109.         }
  110.     }
  111.     close(listenfd);
  112.     return 0;
  113. }
上一篇:linux多线程并发服务器模型
下一篇:用PyQt4写的一个迅雷和旋风下载地址解析小程序