I/O reuse method - select

Keywords: Linux Operation & Maintenance network server

I/O multiplexing

I/O complex method: select poll epoll

effect:

  • You can listen to multiple file descriptors at the same time,
    Enables the server to process multiple file descriptors at the same time without introducing multiple processes.

Network programs need to use I/O multiplexing technology:

◼ The TCP server handles both listening sockets and connecting sockets.
◼ The server should process both TCP requests and UDP requests.
◼ The program processes multiple sockets at the same time.
◼ The client program handles both user input and network connections.
◼ The server should listen to multiple ports at the same time.

Although I/O multiplexing can listen to multiple file descriptors at the same time, it is blocked. And when
When multiple file descriptors are ready at the same time, if no additional measures are taken, the program can only process each file descriptor in sequence, which makes the server seem to work in serial. If you want to improve the ability of concurrent processing, you can use multithreading or multi process programming methods.

socket

socket read event generation:

The other side of socket communication closes the connection.
Listen for new link requests on the socket.
There is an unhandled error on the socket.

select system call
#include<sys/select.h>

select returns the number of file descriptors whose value is ready.
If no file descriptor is ready within the timeout, select returns 0.
If select fails, it returns - 1.
n> 0, n file descriptors are ready.

Handle three kinds of events: read event, write event, and exception event.

Set fd_set adds the descriptor to the collection. The total size defaults to 1024 bits.

int FD_ISSET(int fd, fd_set *fdset); // Test whether the bit FD of fdset is set.


It is suitable for scenes with a small number of descriptors.

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include<sys/select.h>
  5 #include<sys/time.h>
  6 
  7 int main()
  8 {
  9     int fd=0;// stdin 0;  stdout 1; stderr 2 assigns the value of the keyboard descriptor to fd
 10 
 11     fd_set fdset;//Define a collection to collect descriptors, which are detected by selet
 12 
 13     while(1)//Cycle detection
 14     {
 15         struct timeval tv={5,0};//Set the timeout of 5 seconds
 16         FD_ZERO(&fdset); //Clear each bit in the entire collection to 0
 17         FD_SET(fd,&fdset);//Add a descriptor to the collection. There is only one descriptor if there are multiple descriptor loops
 18 
 19         int n=select(fd+1,&fdset,NULL,NULL,&tv);//The maximum value of fd+1 descriptor + 1 only detects places with data
 20         if(n==-1)
 21         {
 22             printf("select err\n");
 23             break;
 24         }
 25         else if(n==0)
 26         {
 27             printf("time out\n");
 28         }
 29         else
 30         {
 31             if(FD_ISSET(fd,&fdset))//Detect whether there is data on the descriptor
 32             {
 33                 char buff[128]={0};
 34                 read(fd,buff,127);
 35                 printf("read:%s\n",buff);
 36             }
 37         }
 38     }
 39 
 40 }

TCP

TCP server

1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5 #include<sys/socket.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 #include<assert.h>
  9 #include<sys/select.h>
 10 #include<sys/time.h>
 11 
 12 #define MAX 10
 13 int socket_init();
 14 
 15 void fds_init(int fds[])//Clear descriptor all to - 1
 16 {
 17     if(fds==NULL)
 18     {
 19         return;
 20     }
 21     for(int i=0;i<MAX;i++)
 22     {
 23         fds[i]=-1;
 24     }
 25 }
 26 void fds_add(int fd,int fds[])//Adds a descriptor to an idle collection
 27 {
 28     if(fds==NULL)
 29     {
 30         return;
 31     }
 32     for(int i=0;i<MAX;i++)
 33     {
 34         if(fds[i]==-1)
 35         {
 36             fds[i]=fd;
 37             break;
 38         }
 39     }
 40 }
 41 void fds_del(int fd,int fds[])//Remove descriptor from collection
 42 {
 43     if(fds==NULL)
 44     {
 45         return;
 46     }
 47     for(int i=0;i<MAX;i++)
 48     {
 49         if(fds[i]==fd)
 50         {
 51             fds[i]=-1;
 52             break;
 53         }
 54     }
 55 }
 56 int main()
 57 {
 58     int sockfd=socket_init();
 59     assert(sockfd!=-1);
 60     int fds[MAX];//Save descriptor in array
 61 
 62     fds_init(fds);//The initialization array values are - 1, which means that the array is empty
 63 
 64     fds_add(sockfd,fds);//Adds a listener socket to the array
 65 
 66     fd_set fdset;//Set - > select
 67 
 68     while(1)
 69     {
 70         FD_ZERO(&fdset);//Empty collection
 71         int maxfd=-1;//Record descriptor maximum
 72 
 73         for(int i=0;i<MAX;i++)
 74         {
 75             if(fds[i]==-1)
 76             {
 77                 continue;
 78             }
 79             FD_SET(fds[i],&fdset);//Adds a valid descriptor to the collection
 80             if(maxfd<fds[i])
 81             {
 82                 maxfd=fds[i];
 83             }
 84         }
 85         struct timeval tv={5,0};//Timeout 5 seconds
 86         int n=select(maxfd+1,&fdset,NULL,NULL,&tv);
 87         if(n==-1)
 88         {
 89             continue;
 90         }
 91         else if(n==0)
 92         {
 93             printf("time out\n");
 94             continue;
 95         }
 96         else
 97         {
 98             for(int i=0;i<MAX;i++)//Traverse all descriptors to find ready
 99             {
100                 if(fds[i]==-1)
101                 {
102                     continue;
103                 }
104                 if(FD_ISSET(fds[i],&fdset))
105                 {
106                     if(fds[i]==sockfd)   //Listen for socket sub call accept
107                     {
108                     struct sockaddr_in caddr;
109                     int len=sizeof(caddr);
110 
111                     int c=accept(sockfd,(struct 	sockaddr*)&caddr,&len);
112                     if(c<0)
113                     {
114                         continue;
115                     }
116                     printf("accept c=%d\n",c);
117                     fds_add(c,fds);
118                     }
119                     else           //Connection socket sub call recv
120                     {
121                         char buff[128]={0};
122                         int num=recv(fds[i],buff,127,0);
123                         if(num<=0)
124                         {
125                             close(fds[i]);
126                             fds_del(fds[i],fds);//Removes unused descriptors from the array
127                             printf("cilent close\n");
128                             continue;
129                         }
130                         printf("read:%s\n",buff);
131                         send(fds[i],"ok",2,0);
132                     }
133                 }
134             }
135         }
136     }
137 }
138 
139 int socket_init()
140 {
141     int sockfd=socket(AF_INET,SOCK_STREAM,0);
142     if(sockfd==-1)
143     {
144         return -1;
145     }
146 
147     struct sockaddr_in saddr;
148     memset(&saddr,0,sizeof(saddr));
149     saddr.sin_family=AF_INET;
150     saddr.sin_port=htons(6000);
151     saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
152 
153     int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
154     if(res==-1)
155     {
156         return -1;
157     }
158 
159     res=listen(sockfd,5);
160     if(res==-1)
161     {
162         return -1;
163     }
164     return sockfd;
165 }
                                                                                               
                                                                                                                                                                   

TCP Client

1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<string.h>
  5 #include<assert.h>
  6 #include<sys/socket.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 
 10 int main()
 11 {
 12     int sockfd=socket(AF_INET,SOCK_STREAM,0);//Create socket
 13     assert(sockfd!=-1);
 14 
 15     //bind() / / can be bound, but generally not
 16 
 17     struct sockaddr_in saddr;
 18     memset(&saddr,0,sizeof(saddr));
 19     saddr.sin_family=AF_INET;
 20     saddr.sin_port=htons(6000);
 21     saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
 22 
 23     int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//Three handshakes
 24     assert(res!=-1);
 25     while(1)
 26     {
 27         char buff[128]={0};
 28         printf("input:\n");
 29         fgets(buff,128,stdin);
 30 
 31         if(strncmp(buff,"end",3)==0)
 32         {
 33             break;
 34         }
 35         send(sockfd,buff,strlen(buff),0);
 36 
 37         memset(buff,0,128);
 38         recv(sockfd,buff,127,0);
 39         printf("buff=%s\n",buff);
 40     }
 41     close(sockfd);
 42 }
~                                  

  1. Opposite close descriptor
  2. Send data to the other party
  3. Opposite link

select will return.

Posted by kevbev16 on Fri, 03 Dec 2021 08:14:54 -0800