高并发服务器学习笔记之七:异步IO——poll模型

poll模型和select模型很相似。两者间的主要区别在于我们要如何指定待检查的文件描述符。在select中,我们提供三个集合,在每个集合中标明我们感兴趣的文件描述符。而在poll中我们提供一列文件描述符,并在每个文件描述符上标明我们感兴趣的事件,完整代码戳这里​​​​​​​,用到的系统调用如下

#include 
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd {
int fd; /* 文件描述符 */
short events; /* 监控的事件 */
short revents; /* 监控事件中满足条件返回的事件 */
};
POLLIN普通或带外优先数据可读,即POLLRDNORM | POLLRDBAND
POLLRDNORM-数据可读
POLLRDBAND-优先级带数据可读
POLLPRI 高优先级可读数据
POLLOUT普通或带外数据可写
POLLWRNORM-数据可写
POLLWRBAND-优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
nfds 监控数组中有多少文件描述符需要被监控
timeout 毫秒级等待
-1:阻塞等,#define INFTIM -1 Linux中没有定义此宏
0:立即返回,不阻塞进程
>0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值

如果不再监控某个文件描述符时,可以把pollfd中,fd设置为-1,poll不再监控此

pollfd,下次返回时,把revents设置为0。

下面是poll模型的服务端代码

#include 
#include 
#include 
#include 

#include 
#include 
#include           /* See NOTES */
#include 
#include 
#include  /* superset of previous */
#include 
#include 

#include "public_head.h"
#include "fileio.h"

#define LISTEN_BACKLOG 50
#define MAX_CLIENT	1024

static ssize_t handle_request(int acceptfd)
{
	ssize_t readret = 0;
	char read_buff[256] = { 0 };
	char write_buff[256] = { 0 };


	memset(read_buff, 0, sizeof(read_buff));
	readret = read(acceptfd, read_buff, sizeof(read_buff));
	if (readret == 0)
		return readret;

	printf("acceptfd:%d, recv message:%s\n", acceptfd, read_buff);

	memset(write_buff, 0, sizeof(write_buff));
	sprintf(write_buff, "This is server send message");
	write(acceptfd, write_buff, sizeof(write_buff));

	printf("\n");
	return readret;
}

int main(int argc, char ** argv)
{
	int i = 0;
    int sockfd = 0;
    int acceptfd = 0;
    socklen_t client_addr_len = 0;
    struct sockaddr_in server_addr, client_addr;

    char client_ip[16] = { 0 };

	int ready;
	int clientlen = 0;
	struct pollfd clientfd[MAX_CLIENT];

	for (i = 0; i < MAX_CLIENT; ++i)
		clientfd[i].fd = -1;

    memset(&server_addr, 0, sizeof(server_addr));
    memset(&client_addr, 0, sizeof(client_addr));

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        handle_error("socket");

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(9527);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
		char buff[256] = { 0 };
        close(sockfd);
		strerror_r(errno, buff, sizeof(buff));
        handle_error("bind");
    }

    if(listen(sockfd, LISTEN_BACKLOG) < 0)
    {
        close(sockfd);
        handle_error("listen");
    }

	clientfd[0].fd = sockfd;
	clientfd[0].events = POLLRDNORM;
	clientlen++;
	
    while(1)
    {
		ready = poll(clientfd, clientlen, -1);
		if (ready < 0)
		{
			if(errno == EINTR)
				continue;

			close(sockfd);
			handle_error("poll");
		}
		else if (ready == 0)
		{
			continue;
		}

		if (clientfd[0].revents & POLLRDNORM)
		{
			client_addr_len = sizeof(client_addr);
			if ((acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len)) < 0)
			{
				handle_warning("accept");
				continue;
			}

			memset(client_ip, 0, sizeof(client_ip));
			inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
			printf("client:%s:%d\n", client_ip, ntohs(client_addr.sin_port));

			clientfd[clientlen].fd = acceptfd;
			clientfd[clientlen].events = POLLRDNORM;
			clientlen++;

			if (ready == 1)
				continue;
		}
        
		for (i = 1; i < clientlen; ++i)
		{
			if (clientfd[i].fd < 0)
				continue;

			if (clientfd[i].revents & POLLRDNORM)
			{
				if (handle_request(clientfd[i].fd) <= 0)
				{
					close(clientfd[i].fd);
					clientfd[i].fd = -1;
				}
			}
		}
    }
    
    close(sockfd);

	exit(EXIT_SUCCESS);
}

 

你可能感兴趣的:(一步步打造高并发服务器)