The poll system call mainly solves two problems of the SELECT system call:
- 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
- File descriptor set (Fd_set)
Value - Result parameter
The 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
- Create a socket to listen to ports
- The FD bound port of the socket
- The socket listening
- Initialize the PollFD array
- 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:
- Fd arrays (whether fd_set or pollFD) must be in
The user space
andThe kernel space
Copy back and forth - When the monitored FD array has an event, the entire array needs to be traversed
The ultimate solution is epoll.