I/O复用(select)——回声服务器端/客户端

 一、select

  使用select函数可以将多个文件描述符集中到一起统一监视,监视事件如下:

  • 是否存在待读取数据。
  • 是否可传输无阻塞传输数据。
  • 是否发生异常。

  将关心上述3种事件的文件描述发分别注册到对应参数(readfds,writefds,exceptfds)中去。

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

1、linux

服务器端:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 
 8 #define BUF_SIZE 1024
 9 void error_handling(char * messages);
10 
11 int main(int argc, char *argv[])
12 {
13     if(argc != 2)
14     {
15         printf("Usage : %s <port>
", argv[0]);
16         exit(1);
17     }
18     int serverSock, clientSock;
19     struct sockaddr_in serverAddr, clientAddr;
20     socklen_t clientAddrSize;
21 
22     struct timeval timeout;
23     fd_set reads, cpy_reads;
24     int fd_max, fd_num;
25 
26     char message[BUF_SIZE];
27     int strLen;
28 
29     serverSock =socket(PF_INET, SOCK_STREAM, 0);
30     if(serverSock == -1)
31         error_handling("socket() error");
32 
33     memset(&serverAddr, 0, sizeof(serverAddr));
34     serverAddr.sin_family = AF_INET;
35     serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
36     serverAddr.sin_port = htons(atoi(argv[1]));
37 
38     if(bind(serverSock, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
39         error_handling("bind() error");
40     if(listen(serverSock, 5) == -1)
41         error_handling("listen() error");
42 
43     FD_ZERO(&reads);
44     FD_SET(serverSock, &reads);
45     fd_max = serverSock;
46 
47     puts("Server start...");
48     while(1){
49         cpy_reads = reads;
50         timeout.tv_sec = 5;
51         timeout.tv_usec = 5000;
52 
53         if((fd_num = select(fd_max+1, &cpy_reads, 0, 0, &timeout)) == -1){
54             error_handling("select() error");
55             break;
56         }
57         if(fd_num == 0) continue;
58         for(int i = 0; i <= fd_max; i++){
59             if(FD_ISSET(i, &cpy_reads)){
60                 if(i == serverSock){ // connection request
61                     clientAddrSize = sizeof(clientAddr);
62                     clientSock = accept(serverSock, (struct sockaddr*)&clientAddr, &clientAddrSize);
63                     FD_SET(clientSock, &reads);
64                     if(fd_max < clientSock)
65                         fd_max = clientSock;
66                     printf("connected client: %d
", clientSock);
67                 }
68                 else{ // read message
69                     strLen = read(i, message, BUF_SIZE);
70                     if(strLen == 0){
71                         FD_CLR(i, &reads);
72                         close(i);
73                         printf("close client: %d
", i);
74                     }
75                     else{
76                         write(i, message, strLen);
77                         printf("echo: %d
",i);
78                     }
79                 }
80             }
81         }
82     }
83     close(serverSock);
84     puts("Server close...");
85     return 0;
86 }
87 
88 void error_handling(char * messages)
89 {
90     puts(messages);
91     exit(1);
92 }
View Code

客户端:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 
 8 #define BUF_SIZE 1024
 9 void error_handling(char * messages);
10 
11 int main(int argc, char *argv[])
12 {
13     if(argc != 3)
14     {
15         printf("Usage : %s <IP> <port>
", argv[0]);
16         exit(1);
17     }
18     int sock;
19     struct sockaddr_in serv_addr;
20     char message[BUF_SIZE];
21     int strLen;
22 
23     sock = socket(PF_INET, SOCK_STREAM, 0);
24     if(sock == -1)
25         error_handling("socket() error");
26 
27     memset(&serv_addr, 0, sizeof(serv_addr));
28     serv_addr.sin_family = AF_INET;
29     serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
30     serv_addr.sin_port = htons(atoi(argv[2]));
31 
32     if(connect(sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
33         error_handling("connect() error");
34     else
35         puts("Connected...");
36     while(1){
37         puts("Input message(Q to quit):");
38         fgets(message, BUF_SIZE, stdin);
39         if(!strcmp(message, "q
") || !strcmp(message, "Q
"))
40             break;
41 
42         strLen=strlen(message);
43         write(sock, message, strlen(message));
44         int recvLen = 0;
45         while(recvLen < strLen){
46             int recvCnt = read(sock, &message[recvLen], BUF_SIZE-1);
47             if(recvCnt == -1)
48                 error_handling("read() error");
49             recvLen+=recvCnt;
50         }
51         message[recvLen]=0;
52         printf("Message from server: %s
", message);
53     }
54     close(sock);
55     return 0;
56 }
57 
58 void error_handling(char * messages)
59 {
60     puts(messages);
61     exit(1);
62 }
View Code

2、windows

服务器端:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <WinSock2.h>
 4 
 5 #define BUF_SIZE 1024
 6 void ErrorHandling(char *message);
 7 
 8 int main(int argc, char *argv[])
 9 {
10     if (argc != 2) {
11         printf("Usage : %s <port>
", argv[0]);
12         exit(1);
13     }
14 
15     WSADATA wsa_data;
16     SOCKET server_sock, client_sock;
17     SOCKADDR_IN server_addr, client_addr;
18     TIMEVAL time_out;
19     fd_set reads, temp_reads;
20 
21     int addr_size;
22     int str_len, fd_num;
23     char buf[BUF_SIZE];
24 
25     if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0)
26         ErrorHandling("WSAStartup() error.");
27 
28     server_sock = socket(PF_INET, SOCK_STREAM, 0);
29     if (server_sock == INVALID_SOCKET)
30         ErrorHandling("socket() error.");
31 
32     memset(&server_addr, 0, sizeof(server_addr));
33     server_addr.sin_family = AF_INET;
34     server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
35     server_addr.sin_port = htons(atoi(argv[1]));
36 
37     if (bind(server_sock, (SOCKADDR*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR)
38         ErrorHandling("bind() error.");
39     if (listen(server_sock, 5) == SOCKET_ERROR)
40         ErrorHandling("listen() error.");
41     printf("Server start...
");
42     FD_ZERO(&reads);
43     FD_SET(server_sock, &reads);
44     while (true)
45     {
46         temp_reads = reads;
47         time_out.tv_sec = 5;
48         time_out.tv_usec = 5000;
49         if ((fd_num = select(0, &temp_reads, 0, 0, &time_out)) == SOCKET_ERROR)
50             break;
51         if (fd_num == 0)
52             continue;
53         for (int i = 0; i < reads.fd_count; ++i)
54         {
55             if (FD_ISSET(reads.fd_array[i], &temp_reads))
56             {
57                 if (reads.fd_array[i] == server_sock) // connection request
58                 {
59                     addr_size = sizeof(client_addr);
60                     client_sock = accept(server_sock, (SOCKADDR*)&client_addr, &addr_size);
61                     if (client_sock == INVALID_SOCKET)
62                         ErrorHandling("accept() error.");
63                     FD_SET(client_sock, &reads);
64                     printf("connected client: %d
", client_sock);
65                 }
66                 else // read message
67                 {
68                     str_len = recv(reads.fd_array[i], buf, BUF_SIZE - 1, 0);
69                     if (str_len == 0)
70                     {
71                         FD_CLR(reads.fd_array[i], &reads);
72                         closesocket(temp_reads.fd_array[i]);
73                         printf("close client: %d
", temp_reads.fd_array[i]);
74                     }
75                     else
76                     {
77                         send(reads.fd_array[i], buf, str_len, 0); // echo
78                     }
79                 }
80             }
81         }
82     }
83     closesocket(server_sock);
84     WSACleanup();
85     printf("Server end...
");
86     return 0;
87 }
88 
89 void ErrorHandling(char *message) {
90     fputs(message, stderr);
91     fputc('
', stderr);
92 }
View Code

客户端:

 1 #pragma warning(disable:4996)
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <string.h>
 5 #include <winsock2.h>
 6 
 7 #define BUF_SIZE 1024
 8 void ErrorHandling(char *message);
 9 
10 int main(int argc, char* argv[]) {
11     if (argc != 3) {
12         printf("Usage : %s <IP> <port>
", argv[0]);
13         exit(1);
14     }
15 
16     WSADATA wsaData;
17     SOCKET sock;
18     SOCKADDR_IN serverAddr;
19     char message[BUF_SIZE];
20     int sLen, recvLen;
21 
22     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
23         ErrorHandling("WSAStartup() error");
24 
25     sock = socket(PF_INET, SOCK_STREAM, 0);
26     if (sock == INVALID_SOCKET)
27         ErrorHandling("socket() error");
28 
29     memset(&serverAddr, 0, sizeof(serverAddr));
30     serverAddr.sin_family = AF_INET;
31     serverAddr.sin_addr.s_addr = inet_addr(argv[1]);
32     serverAddr.sin_port = htons(atoi(argv[2]));
33 
34     if (connect(sock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
35         ErrorHandling("connect() error");
36     else
37         printf("Connected.......
");
38     while (1)
39     {
40         fputs("Input message(Q to quit):", stdout);
41         fgets(message, BUF_SIZE, stdin);
42         if (!strcmp(message, "q
") || !strcmp(message, "Q
"))
43             break;
44         sLen = send(sock, message, strlen(message), 0);
45         recvLen = 0;
46         while (recvLen < sLen) {
47             int cnt = recv(sock, message, BUF_SIZE - 1, 0);
48             if (cnt == -1)
49                 ErrorHandling("ercv() error");
50             recvLen += cnt;
51         }
52         message[recvLen] = 0;
53         printf("Message from server: %s
", message);
54     }
55     closesocket(sock);
56     WSACleanup();
57     return 0;
58 }
59 
60 void ErrorHandling(char *message) {
61     fputs(message, stderr);
62     fputc('
', stderr);
63 }
View Code
原文地址:https://www.cnblogs.com/ACGame/p/9914732.html