IO Multiplexing Model--Implementation of poll and poll version of TCP server

The realization and principle of poll function:

Poll is actually similar to select in that it opens up a space in the kernel, but it does not monitor every event, poll monitors a structured set of events.

1. Functional model:

struct pollfd{
	int fd;
	short events;//Monitoring events
	short revents;//Events in place
}

Common events are POLLIN and POLLOUT:

#include <poll.h>
 int poll(struct pollfd *fds, nfds_t nfds, int timeout);
 

2. Principle of poll function:

1. User-defined event arrays to add concerned events to descriptors;
2.poll implements monitoring by copying data into the kernel and then polling traversal monitoring. The performance decreases with the increase of file descriptors.
3. The user judges which event is ready according to the revents returned and then re-operates.
4.poll will not tell the user which descriptor is ready, but tell the user that there are ready events, which require the user to traverse the search;

3. Advantages and disadvantages of poll:

Advantage:
1) The event structure is used to monitor the descriptor, which simplifies the monitoring method of multiple event sets.
2) There is no specific upper limit for descriptors;

Disadvantages:
1) Can not cross-platform;
2) The performance decreases with the increase of descriptors.

Poll has been phased out because its functions can be replaced by other models, and its performance is high, such as epoll; the advantage of select over poll is that poll cannot cross-platform; but poll is nothing compared to epoll.

4. Implementation of poll version of the server:

MakeFile:

poll_server:poll_server.c
    gcc  $^ -o $@
    

poll_server.c :

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>


int startup( int port )
{
    // 1. Create sockets
    int sock = socket(AF_INET,SOCK_STREAM,0);//The second parameter here represents TCP
    if( sock < 0 )
    {
    perror("socket fail...\n");
    exit(2);
    }

    // 2. When TIME_WAIT is resolved, the server cannot be restarted; the server can be restarted immediately.
    int opt = 1;
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = htonl(INADDR_ANY);// Address of any type
    local.sin_port = htons(port);// The port number here can also be specified directly as 8080.
    // 3. Binding port number

    if( bind(sock,(struct sockaddr *)&local,sizeof(local)) < 0 )
    {
    perror("bind fail...\n");
    exit(3);
    }

    // 4. Get a listening socket
    if( listen(sock,5) < 0 )
    {
    perror("listen fail...\n");
    exit(4);
    }
    return sock;
}

int main(int argc,char* argv[] )
{
    if( argc != 2 )
    {
    printf("Usage:%s port\n ",argv[0]);
    return 1;
    }

    // 1. Get a listening socket
    int listen_sock = startup(atoi(argv[1]));//Port numbers are passed in as strings and need to be converted to integers


    // 2. Initialization of Structures - List of Structures to Monitor
    struct pollfd fd_list[1024];
    int num = sizeof(fd_list)/sizeof(fd_list[0]);
    int i = 0;

    for(; i < num ; i++  )
    {
    fd_list[i].fd = -1;// File descriptor
    fd_list[i].events = 0;// Set of events to monitor
    fd_list[i].revents = 0;// Ready Event Set of Concerned Descriptors
    }


    // 3. Add read-only events for file descriptors of interest

     i = 0;
    for( ; i < num; i++ )
    {
    if( fd_list[i].fd == -1 )
    {
        fd_list[i].fd = listen_sock;
        fd_list[i].events = POLLIN;// Concern about Read-Only Events
        break;
    }
    }
    while(1)
    {

       //4. Start calling poll and wait for the file descriptor set of interest to be ready
       switch( poll(fd_list,num,3000) )
       {
       case 0:// The state of the denominator has exceeded before it has changed. timeout Time
           printf("timeout...\n");
           continue;
       case -1:// failed
           printf("poll fail...\n");
           continue;
       default: // Succeed
           {
           //   If it is a listener file descriptor, call accept to accept a new connection
           //   If it is a normal file descriptor, read is called to read the data
           int i = 0;
           for( ;i < num; i++ )
           {
               if( fd_list[i].fd == -1 )
               {
               continue;
               }
               if( fd_list[i].fd == listen_sock && ( fd_list[i].revents & POLLIN ))
               {
               // 1. Provide a connection acceptance service if the listening socket is ready to read

               struct sockaddr_in client;
               socklen_t len = sizeof(client);
               int new_sock = accept(listen_sock,(struct sockaddr *)&client,&len);
               if(new_sock < 0)
               {
                   perror("accept fail...\n ");
                   continue;
               }
               //After obtaining the new file descriptor, add the file descriptor to the array for the next time you care about the file descriptor
               int i = 0;
               for( ; i < num; i++ )
               {
                   if( fd_list[i].fd == -1 )//Place the first value in the array at - 1
                   break;
               }
               if( i < num )
               {
                   fd_list[i].fd= new_sock;
                   fd_list[i].events = POLLIN;
               }
               else
               {
                   close(new_sock);
               }
               printf("get a new link![%s:%d]\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
               continue;
               }

                //2. At this point, we are concerned with ordinary file descriptors.
            //   Provide services to read data at this time
            if( fd_list[i].revents & POLLIN  )
            {
                char buf[1024];
                ssize_t s = read(fd_list[i].fd,buf,sizeof(buf)-1);
                if( s < 0 )
                {
                printf("read fail...\n");
                continue;
                }
                else if( s == 0 )
                {
                printf("client quit...\n");
                close(fd_list[i].fd);
                fd_list[i].fd = -1;
                }
                else
                {
                buf[s] = 0;
                printf("client# %s\n",buf);
                }
            }
           }
           }
           break;
       }
    }
    returrn 0;
}


Keywords: socket Makefile

Added by tarscher on Tue, 17 Sep 2019 17:19:55 +0300