在前面,我们使用了 select 改写了服务器,本文使用 poll 来改写服务器。
1. 程序路径
代码托管在 gitos 上,请使用下面的命令获取:
git clone https://git.oschina.net/ivan_allen/unp.git
如果你已经 clone 过这个代码了,请使用 git pull 更新一下。本节程序所使用的程序路径是 unp/program/echo/multiplexing_poll_server
。
2. 回忆 poll 函数
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ };
如果你忘记了 poll 函数的用法,请参考《poll 函数》。
3. 使用 poll 改写服务器
使用 poll 改写服务器,要比使用 select 函数简单的多。在 poll 这个版本中,我们只需要一个 struct pollfd 类型的数组即可。关于此数组的大小限制,由宏 OPEN_MAX,但是现代的 linux 内核已经将这个宏废弃,所以大家需要使用 POSIX 的 sysconf 函数,并指定其参数 _SC_OPEN_MAX 来动态获取这个值。
在我们的例子中,我只是简单的将 OPEN_MAX 指定为 1024.
服务器伪代码:
#define OPEN_MAX 1024 void server_routine() { // ... struct pollfd fds[OPEN_MAX]; listen(listenfd); // 将 fd 成员初始化为 -1 for (i = 0; i < OPEN_MAX; ++i) fds[i].fd = -1; fds[0].fd = listenfd; fds[0].events = POLLIN; // 监听读事件 while(1) { nready = poll(fds, OPEN_MAX, 0); for(i = 0; i < OPEN_MAX; ++i) { if (fds[i].fd == -1) continue; if (fds[i].fd == listenfd && fds[i].revents & POLLIN) { // 接受新连接 sockfd = accept(listenfd); // 在 fds 找一个空闲位置,将新连接加入 insert(fds, sockfd); if (--nready <= 0) break; } else if(fds[i] & POLLIN) { // 处理客户端数据 ret = doServer(fds[i].fd); if (ret == 0) { close(fds[i].fd); fds[i].fd = -1; } if (--nready <= 0) break; } } } }
4. 程序运行结果
运行方式很简单,和之前的实验没什么两样:
图1 服务器和客户端正常工作
5. 总结
- 掌握 poll 函数