The usage of select in network programming
Note: This paper does not explain the select function, related parameters and structure
select use flow chart
Create with Rapha ë l 2.2.0 define select related variable define the related data of select related variable initiate call select to monitor whether there are new links in the read event new link descriptors put into array and descriptor set batch read link descriptors yesno
Note: socket process is not written
Lines of code to be added in network programming and their significance
1. Define select related variables
int listenfd,connfd,i; /*Socket descriptor / link descriptor (input phase) / variable*/ int nread,maxfd,maxi,sockfd; /*Ready number / maximum link descriptor / used to record the current maximum used subscript of the link descriptor array, reducing useless traversal/ Link descriptor (the difference is that it is used for I/O multiplexing traversal)*/ int client[FD_SETSIZE]; /*Store the entered link descriptor*/ fd_set allest,rset; /*File set descriptor: all sets / readable sets*/
2.select the related data initialization of related variables
maxfd = listenfd; /*Initialize the maximum link descriptor,*/ maxi = -1; for (i = 0; i < FD_SETSIZE; i++) client[i] = -1; FD_ZERO(&allest); /*Empty allset descriptor set*/ FD_SET(listenfd, &allest); /*Add listening descriptor to allset*/
3.select to monitor readable events
rset = allest; nread = select(maxfd+1, &rset, NULL, NULL, NULL); /*Call select to monitor readable events*/
4. Put new link descriptors into array and descriptor set
if (FD_ISSET(listenfd, &rset)) /*Determine whether there is a change in the server socket (whether there is a new link)*/ { cliaddr_lin = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_lin); for (i = 0; i < FD_SETSIZE; i++) { if (client[i] < 0) { client[i] = connfd; / /*New link descriptor in array*/ break; } } FD_SET(connfd, &allest); /* Join connfd from customer to descriptor set */ if (connfd > maxfd) maxfd = connfd; /*New link descriptor*/ if (i > maxi) maxi = i; if (--nread == 0) continue; }
5. Batch read link descriptor
for (i = 0; i <= maxi; i++) { if ((sockfd = client[i]) < 0) continue; if (FD_ISSET(sockfd, &rset)) { if ((n = read (sockfd, buf, MAXLIN)) == 0) { close(sockfd); FD_CLR(sockfd, &allest); client[i] = -1; }else { if (n < 0) perror("read:"); if (n > 0) write(sockfd, buf, n); } if (--nread == 0) break; } }
routine
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #define LINK_NUMBER 20 #define SERV_PORT 8000 #define MAXLIN 100 int main(int argc, char const *argv[]) { int listenfd,connfd,i; int nread,maxfd,maxi,sockfd; int client[FD_SETSIZE]; ssize_t n; fd_set allest,rset; socklen_t cliaddr_lin; struct sockaddr_in servaddr,cliaddr; char buf[MAXLIN],str[INET_ADDRSTRLEN]; listenfd = socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd,LINK_NUMBER); maxfd = listenfd; maxi = -1; for (i = 0; i < FD_SETSIZE; i++) client[i] = -1; FD_ZERO(&allest); FD_SET(listenfd, &allest); while(1) { rset = allest; nread = select(maxfd+1, &rset, NULL, NULL, NULL); if (nread < 0) { perror("select error:"); break; } if (FD_ISSET(listenfd, &rset)) { cliaddr_lin = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_lin); printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); for (i = 0; i < FD_SETSIZE; i++) { if (client[i] < 0) { client[i] = connfd; break; } } if (i == FD_SETSIZE) { perror("too many clients"); exit(1); } FD_SET(connfd, &allest); if (connfd > maxfd) maxfd = connfd; if (i > maxi) maxi = i; if (--nread == 0) continue; } for (i = 0; i <= maxi; i++) { if ((sockfd = client[i]) < 0) continue; if (FD_ISSET(sockfd, &rset)) { if ((n = read (sockfd, buf, MAXLIN)) == 0) { close(sockfd); FD_CLR(sockfd, &allest); client[i] = -1; }else { if (n < 0) { perror("read:"); } if (n > 0) { write(sockfd, buf, n); } } if (--nread == 0) break; } } /*socket*/ /*while(1) { if((n = read(connfd,buf,MAXLIN)) <= 0) { printf("err" ); break; } printf("received from %s at PORT %d::%s\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port),buf); write(connfd,buf,n); } close(connfd);*/ } return 0; }
References and blogs
Linux chat room project – ChatRome (select Implementation)
Detailed explanation of select function of Linux I/O reuse
The second edition of unix network programming