The poll system call mainly solves two problems of the SELECT system call:

  1. The number of file descriptors (fd_setsize = 32) is too small and the value is written using macros, so the maximum number of file descriptors on a 32-bit machine is only 32*32=1024
  2. File descriptor set (Fd_set)Value - Result parameterThe API design is not very good, select system call to pass set, write set, more events are not good segmentation

The poll system calls use the PollFD data structure to represent an array of events, without the restriction of fd_setsize, and support more event types

1. Pollfd structure

The structure of pollfd is:

struct pollfd { int fd; // fd short events; // The fd is interested in events short revents; // The current event of the fd}Copy the code

POLLIN represents readable events, POLLRDNORM represents ordinary message readable events, POLLIN represents more refined listening events than SELECT, and separate fields are used to represent events and results (Events and Revents).

2. The poll function

The poll function has the following signature:

#include <sys/poll.h>

int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
Copy the code

The first argument is a pointer to the first element of a PollFD array, the second argument is the number of elements in the pollFD array, and the third argument is how long the poll function waits in milliseconds before returning.

3. Poll Echo Server instance

Using the poll function to implement echo Server, the whole process is still five steps

  1. Create a socket to listen to ports
  2. The FD bound port of the socket
  3. The socket listening
  4. Initialize the PollFD array
  5. Issue a poll system call to retrieve all pollFd, find and process events
// // Created by cris wang on 2018/6/28. // #include <sys/poll.h> #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <netinet/in.h> #include <stdlib.h> #include <unistd.h> #include <sys/syslimits.h>  int main() { // 1. Socket int Listenfd = socket(AF_INET, SOCK_STREAM, 0); If (listenfd == -1) printf(" Failed to create socket, error: %s (errno: %d)\n", strError (errno), errno); // 2. Unsigned short listenPort = 8090; struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(listenPort); int on = 1; if ((setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)))) { exit(1); } int bindRet = bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)); If (bindRet == -1) {printf(" Socket binding failed, error: %s (errno: %d)\n", strerror(errno), errno); exit(1); Int listenRet = listen(listenfd, 10); If (listenRet == -1) printf(" Socket listening on port failed, error: %s (errno: %d)\n", strError (errno), errno); Printf ("socket listening completed, address: 127.0.0.1:%d", listenPort); Struct Pollfd client[OPEN_MAX]; client[0].fd = listenfd; client[0].events = POLL_IN; for (int i = 1; i < OPEN_MAX; i++) { client[i].fd = -1; } int maxi = 0, i = 0, MAXLEN = 1024; char buf[MAXLEN]; // 4. Poll for (;;) { int nready = poll(client, (maxi + 1), -1); If (client[0].revents & POLL_IN) {// Accept new connection struct sockaddr_in clientaddr; int clilen = sizeof(clientaddr); int connfd = accept(listenfd, (struct sockaddr *) &clientaddr, &clilen); // Find the first available pollfd for (I = 0; i < OPEN_MAX; i++) { if (client[i].fd < 0) { client[i].fd = connfd; break; } } if (i == OPEN_MAX) exit(1); // Set the event client[I]. Events = POLL_MSG; if (i > maxi) maxi = i; if (--nready <= 0) continue; } for (i = 1; i <= maxi; i++) { struct pollfd sockfd = client[i]; if (sockfd.fd < 0) continue; if (sockfd.revents & (POLL_MSG | POLL_ERR)) { int n = recv(sockfd.fd, buf, MAXLEN, 0); If (n = = 0 | | n < 0) {/ / 0 indicates connection is closed < 0 said connection reset close (sockfd. Fd); client[i].fd = -1; } else write(sockfd.fd, buf, n); if (--nready < 0) break; // No more readable fd}}}}Copy the code

Still use good NC, open several terminals with NC to send messages, the program can also be processed normally

nc localhost 8090
Copy the code

4. The poll concluded

The poll system call addresses select’s file descriptor limitations, but it still has the performance disadvantages of select:

  1. Fd arrays (whether fd_set or pollFD) must be inThe user spaceandThe kernel spaceCopy back and forth
  2. When the monitored FD array has an event, the entire array needs to be traversed

The ultimate solution is epoll.