使用Select编写多客户连接的网络服务器
select系统条用允许程同时在多个底层文件描述符上等待输入的到达(或输出的完成)。
一般在linux系统上,标准输入的文件描述符是0;标准输出的文件描述符是1;
标准错误的文件描述符是2;
在Posix定义分别定义为:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO
他们都包含在unistd.h头文件中
以下代码对于并发连接并不能够同时处理,可以在数据处理部分起多线程处理
服务器端代码如下(客户端代码不做修改):
View Code
1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <iostream> 4 #include <netinet/in.h> 5 #include <sys/time.h> 6 #include <sys/ioctl.h> 7 #include <unistd.h> 8 #include <stdlib.h> 9 #include <arpa/inet.h> 10 #include <string.h> 11 12 using namespace std; 13 14 const string SERVER_IP = "192.168.1.105"; 15 const short SERVER_PORT = 9527; 16 const int MAX_CONN_NUM = 5; 17 const int MAX_DATA_LENGTH = 255; 18 19 20 int main(int argc, char** argv) 21 { 22 int server_sockfd, client_sockfd; 23 int server_len, client_len; 24 struct timeval timeout; 25 struct sockaddr_in server_address; 26 struct sockaddr_in client_address; 27 int result; 28 fd_set readfds, testfds; 29 char ch[MAX_DATA_LENGTH] = {0}; 30 31 timeout.tv_sec = 2; 32 timeout.tv_usec = 500000; 33 34 server_sockfd = socket(AF_INET, SOCK_STREAM, 0); 35 36 server_address.sin_family = AF_INET; 37 server_address.sin_addr.s_addr = inet_addr(SERVER_IP.c_str()); 38 server_address.sin_port = htons(SERVER_PORT); 39 server_len = sizeof(server_address); 40 41 bind(server_sockfd, (struct sockaddr*)&server_address, server_len); 42 43 listen(server_sockfd, MAX_CONN_NUM); 44 45 FD_ZERO(&readfds); 46 FD_SET(server_sockfd, &readfds); 47 48 while(1) 49 { 50 int fd; 51 int nread; 52 53 testfds = readfds; 54 55 cout << "server waiting..." << std::endl; 56 result = select(FD_SETSIZE, &testfds, (fd_set*)0, (fd_set*)0, &timeout); // 此处可以设超时时间为(struct timeval*)0,一般设置为0无限期阻塞 57 58 if (result < 1) 59 { 60 cerr << "select failed!" << endl; 61 exit(EXIT_FAILURE); 62 } 63 64 for (fd = 0; fd < FD_SETSIZE; fd++) 65 { 66 if (FD_ISSET(fd, &testfds)) 67 { 68 if (fd == server_sockfd) 69 { 70 client_len = sizeof(client_address); 71 client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_address, (socklen_t*)&client_len); 72 FD_SET(client_sockfd, &readfds); 73 cout << "adding client on fd " << client_sockfd << endl; 74 } 75 else 76 { 77 ioctl(fd, FIONREAD, &nread); 78 79 if (nread == 0) 80 { 81 close(fd); 82 FD_CLR(fd, &readfds); 83 cout << "removing client on fd " << fd << endl; 84 } 85 else 86 { 87 read(fd, ch , MAX_DATA_LENGTH); 88 cout << "serving client on fd " << fd << endl; 89 cout << "receive from client is " << ch << std::endl; 90 strncpy(ch, "Hello Client", MAX_DATA_LENGTH); 91 write(fd, ch, MAX_DATA_LENGTH); 92 sleep(5); 93 } 94 } 95 } 96 } 97 } 98 close(server_sockfd); 99 }