失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 朴素 Select Poll和Epoll网络编程模型实现和分析——Poll模型

朴素 Select Poll和Epoll网络编程模型实现和分析——Poll模型

时间:2019-10-20 03:48:38

相关推荐

朴素 Select Poll和Epoll网络编程模型实现和分析——Poll模型

在《朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型》中,我们分析了它只能支持1024个连接同时处理的原因。但是在有些需要同时处理更多连接的情况下,1024个连接往往是不够的,也就是不能够高并发。那么这个时候我们就可以采用本文介绍的Poll模型。(转载请指明出于breaksoftware的csdn博客)

在使用Poll模型之前,我们需要定义一个保存连接信息的数组

struct pollfd fds[FDS_COUNT];

之后创建异步监听socket、绑定端口和监听端口等行为和《朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型》一文中一模一样,本文就不列出代码了。我们把创建的socket信息赋值给fds数组的第一个元素,并且设定我们需要关注的事件POLLIN——可读。

int timeout;int cur_fds_count;int rc;int index;int expect_events;int error_events;……// 创建socketmemset(fds, 0, sizeof(fds));error_events = POLLERR | POLLNVAL;expect_events = POLLIN;fds[0].fd = listen_sock;fds[0].events = expect_events;cur_fds_count = 1;

cur_fds_count用于记录当前fds数组中有多少个被关心的文件描述符。因为一开始我们只关心监听socket,所以它的初始值是1。

然后我们就要在一个死循环中,不停的调用poll函数,监控我们关心的文件描述符是否发生了状态改变

timeout = (500);while (1) {rc = poll(fds, cur_fds_count, timeout);if (rc < 0) {perror("poll error\n");exit(EXIT_FAILURE);};if (rc == 0) {//perror("poll timeout\n");};

poll函数的返回值和select函数类似。如果返回小于0,则说明发生了错误,我们让程序退出。如果返回了0,则说明poll函数超时。如果大于0,则说明被关心的文件描述符状态发生了改变。但是此时,我们仍然不知道是哪个文件描述符发生了改变,所以我们要遍历fds数组。

int cur_fds_count_temp = cur_fds_count;for (index = 0; index < cur_fds_count_temp; ++index) {

这个时候我们有必要说明下pollfd结构体的定义

struct pollfd {int fd;short events;short revents;};

pollfd中的fd是用于记录我们关心的文件描述符;events表示我们关心的事件,如POLLIN、POLLOUT等。revents是实际发生的事件。于是我们一开始要判断改pollfd是否发生了事件改变

if (fds[index].revents == 0) {continue;}

接着我们判断下发生的事件是否是我们定义的出错事件。

if (fds[index].revents & error_events) {perror("revents error");

如果出错的是监听socket,则我们退出程序。

if (fds[index].fd == listen_sock) {perror("listen sock error");exit(EXIT_FAILURE);}

如果出错的不是监听socket,则它就是客户端接入的socket,我们将它关闭,并且将fds数组的最后一个元素覆盖当前位置,让数组长度减一。这个过程是最精简的数组缩小方式,如果使用新数组去记录,将导致效率降低。

else {close(fds[index].fd);cur_fds_count--;if (index < cur_fds_count) {memcpy(&fds[index], &fds[cur_fds_count], sizeof(fds[cur_fds_count]));memset(&fds[cur_fds_count], 0, sizeof(fds[cur_fds_count]));index--;}cur_fds_count_temp--;continue;}}

我们再看发生的事件是否是我们关心的事件,如果不是,则continue掉,继续处理下一个pollfd。

if (!(fds[index].revents & fds[index].events)) {continue;}

经过上述筛选,剩下的就是我们要正常处理的pollfd了。和Select方式一样,我们先看看其是否是监听socket。如果是,则获取客户端接入的socket值,并记录到数组中。

if (fds[index].fd == listen_sock) {int new_sock;new_sock = accept(listen_sock, NULL, NULL);if (new_sock < 0) {//perror("accept error");if (errno != EWOULDBLOCK) {continue;}exit(EXIT_FAILURE);}else {request_add(1);//set_block_filedes_timeout(new_sock);if (cur_fds_count + 1 < sizeof(fds)) {fds[cur_fds_count].fd = new_sock;fds[cur_fds_count].events = expect_events;cur_fds_count++;}}}

如果不是监听socket,则是客户端接入的socket。我们就读取这个socket中的内容,并写入我们的回包。

else {if (0 == server_read(fds[index].fd)) {server_write(fds[index].fd);}close(fds[index].fd);cur_fds_count--;if (index < cur_fds_count) {memcpy(&fds[index], &fds[cur_fds_count], sizeof(fds[cur_fds_count]));memset(&fds[cur_fds_count], 0, sizeof(fds[cur_fds_count]));index--;}cur_fds_count_temp--;}}}return 0;}

如此,我们便将简单的poll服务器给写完了。我们看下poll模型的处理能力。采用和《朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型》一文中相同的环境和压力,我们看下服务器的数据输出

再看下客户端的输出

可见当前环境下poll模型的处理能力大概是每秒7500次请求。

如果觉得《朴素 Select Poll和Epoll网络编程模型实现和分析——Poll模型》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。