多路IO转接服务器-POLL

Poll(原理和select一样)【也和select一样 不用话太多的精力】

相比select改进的地方

1.最大文件描述符数量可以 > 1024

2.接受事件和处理事件分开select是传入传出参数  描述符集合在一起的,需要自己维护一个client数组

3.但如果链接的client太多效率还是很低【也和select一样是用的轮询机制要逐个遍历才知道 那些client有事件产生

 

 struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */     接收事件
               short revents;    /* returned events */       返回事件
};

 

 #include <poll.h>

       int poll(struct pollfd *fds, nfds_t nfds, int timeout);   第二个参数 和select类似的 都是最大文件描述符+1 ,高速内核要处理多少个文件描述符

#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;
}

猜你喜欢

转载自blog.csdn.net/qq_44065088/article/details/109269917