I/O multiplexing poll function

    The poll function provides functionality similar to select, but it provides additional information when dealing with stream devices.
#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
               /* Return value: the number of ready descriptors if there are ready descriptors, 0 if timed out, -1 if there is an error */
struct pollfd{
    int    fd;            // descriptor to check
    short  events;        // events of interest on fd
    short  revents;       // events that occurred on fd
};

    Each element in the parameter fdarray array is a pollfd structure that specifies the conditions for testing a given descriptor fd. The condition to be tested is specified by the events member, and the function returns the state of the descriptor in the corresponding reevents member. Each of these two members consists of one or more bits that specify a certain condition. The following table lists some constants for specifying the events flag and testing the reevents flag.

    The table is divided into three parts: the first is four constants that handle input, the second is three constants that handle output, and the third is three constants that handle errors. The three constant values ​​in the third part cannot be set in events, but are returned in reevents when the corresponding condition exists.
    poll identifies three types of data: normal, priority band, and high priority.
    For TCP and UDP sockets, the following conditions cause poll to return specific revents.
    (1) All regular TCP data and all UDP data are considered normal data.
    (2) Out-of-band data of TCP is considered as priority-band data.
    (3) When the read half of the TCP connection is closed (for example, a FIN from the peer is received), it is also considered to be normal data, and subsequent read operations will return 0.
    (4) An error in the TCP connection can be regarded as either ordinary data or an error (POLLERR). In either case, subsequent reads will return -1 with errno set to the appropriate value. This can be used to handle conditions such as an RST is received or a timeout occurs.
    (5) A new connection available on the listening socket can be regarded as either normal data or priority data. Most implementations treat it as normal data.
    (6) Completion of a non-blocking connect is considered to make the corresponding socket writable.
    The number of elements in the structure array is specified by the parameter nfds. Historically this parameter was defined as an unsigned long, and Unix98 defined a new data type for this parameter named nfds_t.
    The timeout parameter specifies how long to wait before poll returns, and is a positive value specifying the number of milliseconds that should wait. Its possible values ​​are as follows:
    (1) INFTIM: means waiting forever. The POSIX specification requires INFTIM to be defined in the header file <poll.h>, but many systems still define it in <sys/stropts.h>.
    (2) 0: Return immediately without blocking the process.
    (3) > 0: Wait the specified number of milliseconds.
    If you don't care about a particular descriptor, you can set the fd member of the pollfd structure corresponding to it to a negative number. The poll function will ignore the events member of such a pollfd structure and return with its reevents member set to 0.
    Below is a blocking TCP echo server implemented using the poll function. It uses an array of pollfd structures to maintain client information, and provides a clients array to save the connected client descriptors. When the value is -1, it means that the item is not used.
#include <stdio.h>
#include <errno.h>
#include <poll.h>
#include <strings.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>

#ifndef INFTIM
#define INFTIM	-1
#endif

typedef struct sockaddr	SA;

#define PORT	49877
#define LISTENQ	5
#define	MAXLINE	1024

int main(void){
	struct sockaddr_in	servaddr;
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(PORT);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

	int listenfd = socket(AF_INET, SOCK_STREAM, 0);
	bind(listenfd, (SA *)&servaddr, sizeof(servaddr));
	listen(listenfd, LISTENQ);

	struct pollfd clients[FOPEN_MAX];
	clients[0].fd = listenfd;
	clients[0].events = POLLRDNORM;
	int i = 0;
	for(i=1; i<FOPEN_MAX; i++)
		clients[i].fd = -1;		// -1 indicates available entry
	int maxi = 0;				// max index into clients[] array
	char buf[MAXLINE];
	for(;;){
		int nready = poll(clients, maxi+1, INFTIM);
		if(clients[0].revents & POLLRDNORM){	// new client connection
			struct sockaddr_in cliaddr;
			socklen_t clilen = sizeof(cliaddr);
			int clifd = accept(listenfd, (SA *)&cliaddr, &clilen);
			// Or: int clifd = accept(listenfd, NULL, NULL);
			for(i=1; i<FOPEN_MAX; i++){
				if(clients[i].fd == -1){
					clients[i].fd = clifd;		// save descriptor
					clients[i].events = POLLRDNORM;
					break;
				}
			}
			if(i == FOPEN_MAX){
				printf("too many clients\n");
				continue;
			}
			if(i > maxi)
				maxi = i;
			if(--nready <= 0)	// no more readable descriptors
				continue;
		}
		for(i=1; i<=maxi; i++){		// check all clients for data
			if(clients[i].fd == -1)
				continue;
			if(clients[i].revents & (POLLRDNORM | POLLERR)){
				ssize_t	n;
				if((n = read(clients[i].fd, buf, MAXLINE)) < 0){
					if(errno == ECONNRESET){ //connection reset by client
						close(clients[i].fd);
						clients[i].fd = -1;
					}else{
						printf("read error\n");
					}
				}else if(n == 0){	// connection closed by client
					close(clients[i].fd);
					clients[i].fd == -1;
				}else{
					write(clients[i].fd, buf, n);
				}
				if(--nready <= 0)	// no more readable descriptors
					break;
			}
		}
	}
	return 0;
}

    The reason for checking here that an existing connection's return event contains POLLERR is that some implementations return a POLLERR event when an RST is received on a connection, while others just return a POLLRDNORM event. Regardless of the emotion, read is called here. When an error occurs, read will return this error.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326050270&siteId=291194637