IO multiplexing--poll

Source: Internet
Author: User
Tags socket error htons

1. Basic knowledge

  Poll is a function of the character device driver in Linux. After the Linux 2.5.44 version, poll was replaced by Epoll. The function of poll is to hang the current file pointer to the waiting queue, similar to what the select implements.

The poll mechanism is similar to select in that there is no significant difference in nature with Select, that managing multiple descriptors is also polling and processing according to the state of the descriptor, but poll has no limit on the maximum number of file descriptors. The disadvantage of poll and select is that an array containing a large number of file descriptors is copied in between the user state and the kernel's address space, regardless of whether the file descriptor is ready, and its overhead increases linearly as the number of file descriptors increases.

Poll advantages

(1) Poll () does not require the developer to calculate the maximum file description Fugai size.
(2) poll () is faster when dealing with a large number of file descriptors, compared to select.
(3) It has no limit on the maximum number of connections, because it is stored based on a linked list.
(4) When calling a function, you only need to set the parameters once.

Poll Disadvantages

(1) A large number of FD arrays are copied across the user state and the kernel address space, regardless of whether such replication is meaningful.
(2) As with SELECT, when poll returns, it needs to poll the POLLFD to get a ready descriptor, which can degrade performance
(3) A large number of simultaneous clients may have only a few ready states at a time, so their efficiency will decrease linearly as the number of monitored descriptors increases.

Elect Advantages:
Currently supported on almost all platforms, and its good cross-platform support is one of its advantages
Select Cons:
(1) Each call to select (), you need to copy the FD collection from the user state to the kernel state, the cost of FD is very large, and each call to select () requires the kernel traversal of all the FD passed in, the cost of the FD is also very large.
(2) There is a maximum limit on the number of file descriptors that a single process can monitor, typically 1024 on Linux, which can be improved by modifying the macro definition or even recompiling the kernel, but this also results in a decrease in efficiency
(3) The SELECT function will reset the parameters before each call, which can be cumbersome and degrade performance

2. Poll function

The function format is as follows:

# include <poll.h>int poll (struct POLLFD * FDS, unsigned int nfds, int timeout);

The POLLFD structure is defined as follows:

struct POLLFD {    int fd;         /* File descriptor */short    events;         /* Wait for events */short    revents;       

  

Each pollfd struct specifies a monitored file descriptor that can pass multiple structures, indicating that poll () monitors multiple file descriptors. The events field for each struct is the event mask that monitors the file descriptor, which is set by the user. The Revents field is the action result event mask of the file descriptor, which is set by the kernel when the call returns. Any events requested in the events domain may be returned in the revents domain. The legitimate events are as follows:

The Pollin has data to read.

Pollrdnorm have normal data to read.

Pollrdband has priority data to read.

POLLPRI has urgent data to read.

Pollout write data does not cause blocking.

Pollwrnorm writing normal data does not cause blocking.

Pollwrband Write priority data does not cause blocking.

Pollmsgsigpoll messages are available.

Additionally, the following events may be returned in the revents domain:
Poller An error occurred with the specified file descriptor.

Pollhup the specified file descriptor pending event.

Pollnval The specified file descriptor is illegal.

These events do not make sense in the events field, because they are always returned from revents at the appropriate time.

Using poll () and select () are different, you do not need to explicitly request an exception condition report.
Pollin | Pollpri equivalent to the Read event of select (), Pollout | Pollwrband is equivalent to the Write event of select (). Pollin equivalent to Pollrdnorm | Pollrdband, while pollout is equivalent to Pollwrnorm. For example, to monitor whether a file descriptor is readable and writable at the same time, we can set events to Pollin | Pollout. When poll returns, we can examine the flags in revents, which correspond to the events structure of the file descriptor request. If the Pollin event is set, the file descriptor can be read without blocking. If Pollout is set, the file descriptor can be written without causing blocking. These flags are not mutually exclusive: they may be set at the same time, indicating that the read and write operations of the file descriptor return normally without blocking.

The timeout parameter specifies the number of milliseconds to wait, and poll returns regardless of whether I/O is ready. Timeout is specified as a negative value to indicate an infinite timeout, so that poll () hangs until a specified event occurs, and a timeout of 0 indicates that the poll call immediately returns and lists the file descriptor ready for I/O, but does not wait for other events. In this case, poll (), like its name, returns as soon as it is elected.


Return values and error codes
On success, poll () returns the number of file descriptors that are not 0 in the Revents field in the struct, and if no events occur before the timeout, poll () returns 0; when failed, poll () returns-1, and sets errno to one of the following values:
EBADF the file descriptor specified in one or more structs is invalid.

The address that the Efaultfds pointer points to exceeds the address space of the process.

Eintr the requested event before generating a signal that the call can be re-initiated.

The Einvalnfds parameter exceeds the Plimit_nofile value.

Enomem There is not enough memory available to complete the request.

3. Measure procedure

Write an echo server program, where the client sends information to the server, the server receives the output and sends it back to the client, and the client receives the output to the terminal.

The server-side programs are as follows:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include < netinet/in.h> #include <sys/socket.h> #include <poll.h> #include <unistd.h> #include <sys/ types.h> #define IPADDRESS "127.0.0.1" #define PORT 8787#define MAXLINE 1024#define listenq 5#define OPE N_max 1000#define inftim-1//Function declaration//Create socket and bind static int socket_bind (const char* ip,int port);//io Multiplexing pollstatic VO ID do_poll (int listenfd);//handle multiple connections static void Handle_connection (struct POLLFD *connfds,int num); int main (int Argc,char *    Argv[]) {int listenfd,connfd,sockfd;    struct sockaddr_in cliaddr;    Socklen_t Cliaddrlen;    LISTENFD = Socket_bind (Ipaddress,port);    Listen (LISTENFD,LISTENQ);    Do_poll (LISTENFD); return 0;}    static int Socket_bind (const char* ip,int port) {int listenfd;    struct sockaddr_in servaddr;    LISTENFD = socket (af_inet,sock_stream,0);        if (LISTENFD = =-1) {perror ("Socket Error:"); EXIT (1);    } bzero (&servaddr,sizeof (SERVADDR));    servaddr.sin_family = af_inet;    Inet_pton (AF_INET,IP,&AMP;SERVADDR.SIN_ADDR);    Servaddr.sin_port = htons (port);        if (Bind (LISTENFD, (struct sockaddr*) &servaddr,sizeof (servaddr)) = =-1) {perror ("Bind error:");    Exit (1); } return LISTENFD;}    static void Do_poll (int listenfd) {int connfd,sockfd;    struct sockaddr_in cliaddr;    Socklen_t Cliaddrlen;    struct POLLFD Clientfds[open_max];    int maxi;    int i;    int nready;    Add Listener Descriptor CLIENTFDS[0].FD = LISTENFD;    Clientfds[0].events = Pollin;    Initialize the Client connection descriptor for (i = 1;i < open_max;i++) CLIENTFDS[I].FD =-1;    Maxi = 0;    cyclic processing for (;;)        {//Gets the number of available descriptors Nready = poll (Clientfds,maxi+1,inftim);            if (Nready = =-1) {perror ("poll error:");        Exit (1); }//test if the listener descriptor is ready if (Clientfds[0].revents & pollin) {Cliaddrlen = sizeof (CLIADDR);            Accept the new connection if ((CONNFD = Accept (LISTENFD, (struct sockaddr*) &cliaddr,&cliaddrlen)) = =-1)                {if (errno = = eintr) continue;                   else {perror ("Accept error:");                Exit (1);            }} fprintf (stdout, "accept a new client:%s:%d\n", Inet_ntoa (CLIADDR.SIN_ADDR), cliaddr.sin_port);  Add a new connection descriptor to the array for (i = 1;i < open_max;i++) {if (Clientfds[i].fd <                    0) {clientfds[i].fd = CONNFD;                Break                }} if (i = = Open_max) {fprintf (stderr, "too many clients.\n");            Exit (1);            }//Adds a new descriptor to the read descriptor collection clientfds[i].events = Pollin;            Record number of client connection sockets maxi = (i > Maxi? i:maxi);           if (--nready <= 0)     Continue    }//Handle customer Connection Handle_connection (Clientfds,maxi);    }}static void handle_connection (struct POLLFD *connfds,int num) {int i,n;    Char Buf[maxline];    memset (Buf,0,maxline);        for (i = 1;i <= num;i++) {if (CONNFDS[I].FD < 0) continue; Test whether the customer descriptor is ready if (Connfds[i].revents & Pollin) {//Receive client sent information n = read (Connfds[i]            . Fd,buf,maxline);                if (n = = 0) {close (CONNFDS[I].FD);                CONNFDS[I].FD =-1;            Continue            }//printf ("Read MSG is:");            Write (stdout_fileno,buf,n);        Send buf Write (connfds[i].fd,buf,n) to the client; }    }}

The

Client code looks like this:

#include <netinet/in.h> #include <sys/socket.h> #include <stdio.h> #include <string.h># Include <stdlib.h> #include <poll.h> #include <time.h> #include <unistd.h> #include <sys/ types.h> #define MAXLINE 1024#define IPADDRESS "127.0.0.1" #define Serv_port 8787#define Max (b) (a > B)?    a:bstatic void handle_connection (int sockfd); int main (int argc,char *argv[]) {int sockfd;    struct sockaddr_in servaddr;    SOCKFD = socket (af_inet,sock_stream,0);    Bzero (&servaddr,sizeof (SERVADDR));    servaddr.sin_family = af_inet;    Servaddr.sin_port = htons (Serv_port);    Inet_pton (AF_INET,IPADDRESS,&AMP;SERVADDR.SIN_ADDR);    Connect (SOCKFD, (struct sockaddr*) &servaddr,sizeof (SERVADDR));    Processing Connection Descriptor Handle_connection (SOCKFD); return 0;}    static void handle_connection (int sockfd) {char sendline[maxline],recvline[maxline];    int maxfdp,stdineof;    struct POLLFD pfds[2];    int n; Add Connection Descriptor PFDs[0].FD = SOCKFD;    Pfds[0].events = Pollin;    Add standard input Descriptor PFDS[1].FD = Stdin_fileno;    Pfds[1].events = Pollin;    for (;;)        {poll (pfds,2,-1);            if (Pfds[0].revents & Pollin) {n = read (sockfd,recvline,maxline);                    if (n = = 0) {fprintf (stderr, "Client:server is closed.\n");            Close (SOCKFD);        } write (Stdout_fileno,recvline,n); }//test whether the standard input is ready if (Pfds[1].revents & Pollin) {n = read (stdin_fileno,sendline,maxline            );        if (n = = 0) {shutdown (SOCKFD,SHUT_WR);            Continue        } write (Sockfd,sendline,n); }    }}

  4. Program Test Results

IO multiplexing--poll

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.