I/O多路复用——select

select

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

有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。fd_set 使用数组实现,数组大小使用 FD_SETSIZE 定义。

timeout 为超时参数,调用 select 会一直阻塞直到有描述符的事件到达或者等待的时间超过 timeout。

成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0。

select使用实例

  服务端

  1 #include <sys/types.h>
  2 #include <sys/socket.h>
  3 #include <netinet/in.h>
  4 #include <arpa/inet.h>
  5 #include <unistd.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <strings.h>
  9 #include <sys/wait.h>
 10 #include <string.h>
 11 #include <errno.h>
 12 #define DEFAULT_PORT 6666
 13 int main( int argc, char ** argv){
 14     int serverfd,acceptfd; /* 监听socket: serverfd,数据传输socket: acceptfd */
 15     struct sockaddr_in my_addr; /* 本机地址信息 */
 16     struct sockaddr_in their_addr; /* 客户地址信息 */
 17     unsigned int sin_size, myport=6666, lisnum=10;
 18     if ((serverfd = socket(AF_INET , SOCK_STREAM, 0)) == -1) {
 19        perror("socket" );
 20        return -1;
 21     }
 22     printf("socket ok \n");
 23     my_addr.sin_family=AF_INET;
 24     my_addr.sin_port=htons(DEFAULT_PORT);
 25     my_addr.sin_addr.s_addr = INADDR_ANY;
 26     bzero(&(my_addr.sin_zero), 0);
 27     if (bind(serverfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr )) == -1) {
 28         perror("bind" );
 29         return -2;
 30     }
 31     printf("bind ok \n");
 32     if (listen(serverfd, lisnum) == -1) {
 33         perror("listen" );
 34         return -3;
 35     }
 36     printf("listen ok \n");
 37     
 38     fd_set client_fdset;    /*监控文件描述符集合*/
 39     int maxsock;            /*监控文件描述符中最大的文件号*/
 40     struct timeval tv;        /*超时返回时间*/
 41     int client_sockfd[5];   /*存放活动的sockfd*/
 42     bzero((void*)client_sockfd,sizeof(client_sockfd));
 43     int conn_amount = 0;    /*用来记录描述符数量*/
 44     maxsock = serverfd;
 45     char buffer[1024];
 46     int ret=0;
 47     while(1){
 48         /*初始化文件描述符号到集合*/
 49         FD_ZERO(&client_fdset);
 50         /*加入服务器描述符*/
 51     FD_SET(serverfd,&client_fdset);
 52     /*设置超时时间*/
 53     tv.tv_sec = 30; /*30秒*/
 54     tv.tv_usec = 0;
 55     /*把活动的句柄加入到文件描述符中*/
 56     for(int i = 0; i < 5; ++i){
 57 /*程序中Listen中参数设为5,故i必须小于5*/
 58         if(client_sockfd[i] != 0){
 59             FD_SET(client_sockfd[i], &client_fdset);
 60         }
 61      }
 62     /*printf("put sockfd in fdset!\n");*/
 63     /*select函数*/
 64     ret = select(maxsock+1, &client_fdset, NULL, NULL, &tv);
 65     if(ret < 0){
 66         perror("select error!\n");
 67         break;
 68     }
 69     else if(ret == 0){
 70         printf("timeout!\n");
 71         continue;
 72     }
 73     /*轮询各个文件描述符*/
 74     for(int i = 0; i < conn_amount; ++i){
 75     /*FD_ISSET检查client_sockfd是否可读写,>0可读写*/
 76         if(FD_ISSET(client_sockfd[i], &client_fdset)){
 77             printf("start recv from client[%d]:\n",i);
 78             ret = recv(client_sockfd[i], buffer, 1024, 0);
 79             if(ret <= 0){
 80             printf("client[%d] close\n", i);
 81             close(client_sockfd[i]);
 82             FD_CLR(client_sockfd[i], &client_fdset);
 83             client_sockfd[i] = 0;
 84             }
 85             else{
 86          printf("recv from client[%d] :%s\n", i, buffer);
 87             }
 88         }
 89     }
 90     /*检查是否有新的连接,如果收,接收连接,加入到client_sockfd中*/
 91     if(FD_ISSET(serverfd, &client_fdset)){
 92         /*接受连接*/
 93         struct sockaddr_in client_addr;
 94         size_t size = sizeof(struct sockaddr_in);
 95 int sock_client = accept(serverfd, (struct sockaddr*)(&client_addr), (unsigned int*)(&size));
 96 if(sock_client < 0){
 97     perror("accept error!\n");
 98     continue;
 99 }
100 /*把连接加入到文件描述符集合中*/
101 if(conn_amount < 5){
102     client_sockfd[conn_amount++] = sock_client;
103     bzero(buffer,1024);
104     strcpy(buffer, "this is server! welcome!\n");
105     send(sock_client, buffer, 1024, 0);
106     printf("new connection client[%d] %s:%d\n", conn_amount, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
107     bzero(buffer,sizeof(buffer));
108     ret = recv(sock_client, buffer, 1024, 0);
109     if(ret < 0){
110         perror("recv error!\n");
111         close(serverfd);
112         return -1;
113     }
114     printf("recv : %s\n",buffer);
115     if(sock_client > maxsock){
116         maxsock = sock_client;
117     }
118     else{
119         printf("max connections!!!quit!!\n");
120         break;
121     }
122    }
123   }
124 }
125 for(int i = 0; i < 5; ++i){
126     if(client_sockfd[i] != 0){
127         close(client_sockfd[i]);
128     }
129 }
130 close(serverfd);
131 return 0;    
132 }
View Code

  客户端 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <sys/types.h>
 6 #include <sys/socket.h>
 7 #include <netinet/in.h>
 8 #include <arpa/inet.h>
 9 #include <errno.h>
10 #define DEFAULT_PORT 6666
11 int main( int argc, char * argv[]){
12     int connfd = 0;
13     int cLen = 0;
14     struct sockaddr_in client;
15     if(argc < 2){
16         printf(" Uasge: clientent [server IP address]\n");
17         return -1;
18     }    
19     client.sin_family = AF_INET;
20     client.sin_port = htons(DEFAULT_PORT);
21     client.sin_addr.s_addr = inet_addr(argv[1]);
22     connfd = socket(AF_INET, SOCK_STREAM, 0);
23     if(connfd < 0){
24         perror("socket" );
25         return -1;
26     }
27     if(connect(connfd, (struct sockaddr*)&client, sizeof(client)) < 0){
28          perror("connect" );
29         return -1;
30     }
31     char buffer[1024];
32     bzero(buffer,sizeof(buffer));
33     recv(connfd, buffer, 1024, 0);
34     printf("recv : %s\n", buffer);
35     bzero(buffer,sizeof(buffer));
36     strcpy(buffer,"this is client!\n");
37     send(connfd, buffer, 1024, 0);
38     while(1){
39         bzero(buffer,sizeof(buffer));
40         scanf("%s",buffer);
41         int p = strlen(buffer);
42         buffer[p] = '\0';
43         send(connfd, buffer, 1024, 0);
44         printf("i have send buffer\n");
45     }
46     close(connfd);
47     return 0;
48 }
View Code

 

  

posted @ 2019-04-27 23:09  unique_ptr  阅读(227)  评论(0编辑  收藏  举报