C++: Implementation of multi-channel IO transfer with select

Basic idea of select

Set LFD as port reuse

The file descriptors that need to be monitored are sent to the kernel for listening through select. When an event occurs, the number of events is returned through select. Then scan the set of file descriptors one by one to process the event.

Include file:

< sys/select.h>

The function structure of select is as follows:

int select(int nfds, fd_ set * readfds, fd_ set *writefds, fd_ set *exceptfds, struct timeval *timeout);

Parameter description

fd_ Set: the structure of file descriptor set. It is a 1024 bitmap. 0 means that there is no event and 1 means that there is an event. The converted format is:
typedef struct
{
long int__ fds_ bits[1024/(8*8))];
}
NFDS: the maximum number of file descriptors being monitored is + 1
readfds: read set is an incoming and outgoing parameter. The incoming parameter is the set of file descriptors that need to be read and monitored, and the outgoing parameter is the changed file descriptor<
writefds: write file descriptor (same as above, incoming and outgoing parameters)
execptfds: exception file descriptor (same as above, incoming and outgoing parameters)
timeout:
0: no blocking, return immediately after scanning
greater than 0: blocking waiting time is long, return immediately when no event occurs before arrival time
null: permanent blocking wait event
Return:
– 1: listening failure
greater than 0: number of events

Correlation bit operation

1. Remove FD from set
void FD_ CLR(int fd,set *set);
2. Judge whether the descriptor is in the set
2_ ISSET(int fd,fd_ set *set);
3. Put descriptors into the set
void FD_ SET(int fd,fd_ Set * set)
4. Empty set
void FD_ ZERO(fd_ set *set)

Advantages and disadvantages of select

Advantages: cross platform, supported on both windows and Linux
disadvantages: it involves copying back and forth between user area and kernel area. When there are many links but few active users, the efficiency is low, and the maximum number of listeners can not exceed 1024.

Select code

Insert code snippet here
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>	
#include<netinet/in.h>
#include<ctype.h>
#include<sys/socket.h>
#include<sys/select.h>

#include<iostream>
#include<string>

using namespace  std;
int main()
{
    /*1.create socket*/
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    if(lfd<0)
    {
        perror("socket error!");
        return -1;
    }
    /*Setting up port multiplexing*/
    int opt=1;
    setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
    /*Initialize server-side address structure*/
    struct sockaddr_in  sevr;
    bzero(&sevr,sizeof(sevr));
    sevr.sin_family=AF_INET;
    sevr.sin_port=htons(9090);
    sevr.sin_addr.s_addr=htonl(INADDR_ANY);

    /*Binding socket address structure*/
    int ret=bind(lfd,(sockaddr *)&sevr,sizeof(sockaddr));
    if(ret<0)
    {
        perror("bind error!");
        return -1;
    }
    /*Listening to events*/
    int re= listen(lfd,128);

    /*Create a collection of listened read events*/
    fd_set readfds;
    fd_set tmpfds;

    /*Initialization*/
    FD_ZERO(&readfds);
    FD_ZERO(&tmpfds);
    /*Adding file descriptors to the read event set*/
    FD_SET(lfd,&readfds);
    int maxfd=lfd+1;
    int cfd;
    while(1)
    {
        tmpfds=readfds;
        /*Give the event descriptors in the collection to the kernel to listen */
        /* Listening range, max file descriptors + 1*/
        int nready=select(maxfd+1,&tmpfds,NULL,NULL,NULL);
        cout<<nready<<endl;
        if(nready<0)
        {
            /*Event Terminal*/
            if(errno==EINTR)
                continue;
	    cout<<"select error"<<endl;
            break;
        }

        /*There is a client connection request*/
        if(FD_ISSET(lfd,&tmpfds))
        {
            cfd=accept(lfd,NULL,NULL);
            if(cfd<=0)
            {
                cout<<"accept error"<<endl;
                return -1;
            }
            /*Add cfd to the listener set */
            FD_SET(cfd,&readfds);

            /*Modify the value of maxfds*/
            if(maxfd<=cfd)
            {
                maxfd=cfd;
            }
             /* Only listen events, no read content events*/
            if(--nready==0)
            {
                cout<<"continue"<<endl;
                continue;
            }
        }

        /*Polling to find out the descriptors of read events*/
        for(int i=0;i<=maxfd;i++)
        {
            cout<<i <<endl;
            if(FD_ISSET(i,&tmpfds))
            {
                cout<<"is in cfds"<<endl;
                char buf[1024]={0};
                int n=read(i,buf,sizeof(buf));
                if(n<=0)
                {
                    /*close*/
                    cout<<"read error"<<endl;
                    close(i);
                    /*dele*/
                    FD_CLR(i,&readfds);
                }
                else
                {
                    cout<<buf<<endl;
                    for(int k=0;k<n;k++)
                    {
                        buf[k]=toupper(buf[k]);
                    }
                    write(i,buf,n);
                }

            }
        }
    }

    close(lfd);
    close(cfd);
    return 0;
}


Read More: