Multi-channel IO transfer server-POLL

Poll (the principle is the same as select) [the same as select without too much energy]

Compared with select

1. The maximum number of file descriptors can be> 1024

2. Receive events and process events separately [ select is a collection of incoming and outgoing parameters and descriptors, and you need to maintain a client array by yourself ]

3. But if there are too many clients connected, the efficiency is still very low [ also the same polling mechanism as select ] It is necessary to traverse one by one to know that those clients have events

 

 struct pollfd {                int fd; /* file descriptor */                short events; /* requested events */ Receive events                short revents; /* returned events */ Return events };




 

 #include <poll.h>

       int poll(struct pollfd *fds, nfds_t nfds, int timeout); The second parameter, similar to select, is the maximum file descriptor +1, how many file descriptors the high-speed kernel has to process

#include <iostream>
#include <poll.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>


using namespace std;

#define SERVER_PORT 8888
#define MAX_LINE 512
#define OPEN_MAX 1024

static int Debug = 1;

int
main(int argc, char*argv[])
{
	int i, j, maxi, listenfd, connfd, sockfd;
	int nready;
	ssize_t n;

	char buf[MAX_LINE], str[INET_ADDRSTRLEN];

	socklen_t clie_addr_len;
	struct pollfd client[OPEN_MAX];
	struct sockaddr_in clie_addr, serv_addr;
	
	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	
	int opt = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));

	memset(&serv_addr, 0, sizeof(serv_addr));

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERVER_PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

	listen(listenfd, OPEN_MAX);

	client[0].fd = listenfd;
	client[0].events = POLLIN;

	for(i=1; i<OPEN_MAX; i++)
		client[i].fd = -1;

	maxi = 0;

	if(Debug)printf("-----listening-----\n");

	while(true){
		nready = poll(client, maxi+1, -1);
		if(client[0].revents & POLLIN){ // if has client connect
			clie_addr_len = sizeof(clie_addr);
			connfd = accept(listenfd, (struct sockaddr*)&clie_addr, &clie_addr_len);
			// print client IP and PORT
			if(Debug)printf("client IP:%s, PORT:%d \n",
				inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),
				ntohs(clie_addr.sin_port));

			for(i=1; i<OPEN_MAX; i++){ // save connfd to fds
				if(client[i].fd < 0){
					client[i].fd = connfd;
					break;
				}
			}
		
			if(i == OPEN_MAX){
				perror("connect client too many");
				exit(1);
			}
				
			client[i].events = POLLIN;    // listening connfd read event
			
			if(i > maxi)
				maxi = i;

			if(--nready == 0)
				continue;
		}
		
		for(i=1; i<=maxi; i++){
			if((sockfd = client[i].fd) < 0)
				continue;

			if(client[i].revents & POLLIN){
				if((n = read(sockfd, buf, sizeof(buf)))       < 0){
					if(errno == ECONNRESET){	/*RST分节*/
						if(Debug)printf("client[%d] abort connection \n", i);
						close(sockfd);
						client[i].fd = -1;
					}else{
						perror("read error");
						close(sockfd);
						client[i].fd = -1;
					}
				}else if(n == 0){
					if(Debug)printf("client[%d] closed connection\n", i);
					close(sockfd);
					client[i].fd = -1;
				}else{
					if(errno == EINTR){
						if(Debug)printf("client[%d] read is interupted by signal\n", i);
						close(sockfd);
						client[i].fd = -1;
						if(--nready == 0)break;
						else continue;
					}
					
					for(j=0; j<n; j++)
						buf[j] = toupper(buf[j]);
					write(sockfd, buf, n);
					if(Debug)printf("server has reply client\n");
					if(--nready == 0)break;
				}
			}
			
		}
	}
	
	return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_44065088/article/details/109269917