server with select
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<sys/socket.h> 4 #include<unistd.h> 5 #include<stdlib.h> 6 #include<errno.h> 7 #include<arpa/inet.h> 8 #include<netinet/in.h> 9 #include<string.h> 10 #include<signal.h> 11 #include<sys/wait.h> 12 13 #define ERR_EXIT(m) 14 do { 15 perror(m); 16 exit(EXIT_FAILURE); 17 } while (0) 18 19 20 int main(void) 21 { 22 23 signal(SIGPIPE, SIG_IGN); 24 int listenfd; //被动套接字(文件描述符),即只可以accept, 监听套接字 25 if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 26 // listenfd = socket(AF_INET, SOCK_STREAM, 0) 27 ERR_EXIT("socket error"); 28 29 struct sockaddr_in servaddr; 30 memset(&servaddr, 0, sizeof(servaddr)); 31 servaddr.sin_family = AF_INET; 32 servaddr.sin_port = htons(5188); 33 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 34 /* servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */ 35 /* inet_aton("127.0.0.1", &servaddr.sin_addr); */ 36 37 int on = 1; 38 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 39 ERR_EXIT("setsockopt error"); 40 41 if (bind(listenfd, (struct sockaddr*)&servaddr,sizeof(servaddr)) < 0) 42 ERR_EXIT("bind error"); 43 44 if (listen(listenfd, SOMAXCONN) < 0) //listen应在socket和bind之后,而在accept之前 45 ERR_EXIT("listen error"); 46 47 struct sockaddr_in peeraddr; //传出参数 48 socklen_t peerlen = sizeof(peeraddr); //传入传出参数,必须有初始值 49 50 int conn; // 已连接套接字(变为主动套接字,即可以主动connect) 51 int i; 52 int client[FD_SETSIZE]; 53 int maxi = 0; // client数组中最大不空闲位置的下标 54 for (i = 0; i < FD_SETSIZE; i++) 55 client[i] = -1; 56 57 int nready; 58 int maxfd = listenfd; 59 fd_set rset; 60 fd_set allset; 61 FD_ZERO(&rset); 62 FD_ZERO(&allset); 63 FD_SET(listenfd, &allset); 64 65 while (1) { 66 rset = allset; 67 nready = select(maxfd + 1, &rset, NULL, NULL, NULL); 68 if (nready == -1) { 69 if (errno == EINTR) 70 continue; 71 ERR_EXIT("select error"); 72 } 73 74 if (nready == 0) 75 continue; 76 77 if (FD_ISSET(listenfd, &rset)) { 78 79 conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen); //accept不再阻塞 80 if (conn == -1) 81 ERR_EXIT("accept error"); 82 83 for (i = 0; i < FD_SETSIZE; i++) { 84 if (client[i] < 0) { 85 client[i] = conn; 86 if (i > maxi) 87 maxi = i; 88 break; 89 } 90 } 91 92 if (i == FD_SETSIZE) { 93 fprintf(stderr, "too many clients "); 94 exit(EXIT_FAILURE); 95 } 96 97 printf("recv connect ip=%s port=%d ", inet_ntoa(peeraddr.sin_addr), 98 ntohs(peeraddr.sin_port)); 99 100 FD_SET(conn, &allset); 101 if (conn > maxfd) 102 maxfd = conn; 103 104 if (--nready <= 0) 105 continue; 106 } 107 108 for (i = 0; i <= maxi; i++) { 109 conn = client[i]; 110 if (conn == -1) 111 continue; 112 113 if (FD_ISSET(conn, &rset)) { 114 115 char recvbuf[1024] = {0}; 116 int ret = read(conn, recvbuf, 1024); 117 if (ret == -1) 118 ERR_EXIT("readline error"); 119 else if (ret == 0) { //客户端关闭 120 printf("client close "); 121 FD_CLR(conn, &allset); 122 client[i] = -1; 123 close(conn); 124 } 125 126 fputs(recvbuf, stdout); 127 write(conn, recvbuf, strlen(recvbuf)); 128 129 if (--nready <= 0) 130 break; 131 } 132 } 133 134 135 } 136 137 return 0; 138 }