select server

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 }

ref1      ref2

原文地址:https://www.cnblogs.com/forcheryl/p/4664856.html