一、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 }
客户端:
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 }
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 }
客户端:
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 }