- 浏览: 140257 次
文章分类
最新评论
poll 函数提供的功能与 select 类似,不过在处理流设备时,它能提供额外的信息。
其中参数 fdarray 数组中的每一个元素都是一个 pollfd 结构,用于指定测试某个给定描述符 fd 的条件。要测试的条件由 events 成员指定,函数在相应的 revents 成员中返回该描述符的状态。这两个成员中的每一个都由指定某个特定条件的一位或多位构成。下表列出了用于指定 events 标志以及测试 revents 标志的一些常值。
该表被分为三个部分:第一部分是处理输入的四个常值,第二部分是处理输出的三个常值,第三部分是处理错误的三个常值。其中第三部分的三个常值不能在 events 中设置,但是当相应条件存在时就在 revents 中返回。
poll 识别三类数据:普通、优先级带(priority band)和高优先级。
就 TCP 和 UDP 套接字而言,以下条件会引起 poll 返回特定的 revents。
(1)所有正规 TCP 数据和所有 UDP 数据都被认为是普通数据。
(2)TCP 的带外数据被认为是优先级带数据。
(3)当 TCP 连接的读半部关闭时(譬如收到了一个来自对端的 FIN),也被认为是普通数据,随后的读操作将返回 0。
(4)TCP 连接存在错误既可以认为是普通数据,也可以认为是错误(POLLERR)。无论哪种情况,随后的读操作将返回 -1,并把 errno 设置成合适的值。这可以用于处理诸如接收到 RST 或发生超时等条件。
(5)在监听套接字上有新的的连接可用既可以认为是普通数据,也可以认为是优先级数据。大多数实现视为普通数据。
(6)非阻塞式 connect 的完成被认为是使相应套接字可写。
结构数组中元素的个数是由参数 nfds 指定的。历史上该参数被定义为无符号长整型,Unix98 为该参数定义了名为 nfds_t 的新的数据类型。
timeout 参数指定 poll 返回前至多等待多长时间,它是一个指定应等待毫秒数的正值。它的可能取值如下:
(1)INFTIM:表示永远等待。POSIX 规范要求在头文件 <poll.h> 中定义 INFTIM,不过许多系统仍然把它定义在 <sys/stropts.h> 中。
(2)0:立即返回,不阻塞进程。
(3)> 0:等待指定数目的毫秒数。
如果不关心某个特定描述符,那么可以把与它对应的 pollfd 结构的 fd 成员设置成一个负数。poll 函数将忽略这样的 pollfd 结构的 events 成员,返回时将它的 revents 成员的值置为 0。
下面是使用 poll 函数实现的一个阻塞式的 TCP 回射服务器。它使用了一个 pollfd 结构的数组来维护客户信息,另外提供了一个 clients 数组来保存连接的客户端描述符,当其中的值为 -1 时表示所在项未使用。
这里检查某个现有连接的返回事件包含 POLLERR 的原因在于:有些实现在一个连接上接收到 RST 时返回的是 POLLERR 事件,而其他的返回的只是 POLLRDNORM 事件。不论哪一种情绪,这里都调用 read。当有错误发生时,read 将返回这个错误。
#include <poll.h> int poll(struct pollfd *fdarray, unsigned long nfds, int timeout); /* 返回值:若有就绪描述符则为其数目,若超时则为 0,若出错则为 -1 */ struct pollfd{ int fd; // descriptor to check short events; // events of interest on fd short revents; // events that occurred on fd };
其中参数 fdarray 数组中的每一个元素都是一个 pollfd 结构,用于指定测试某个给定描述符 fd 的条件。要测试的条件由 events 成员指定,函数在相应的 revents 成员中返回该描述符的状态。这两个成员中的每一个都由指定某个特定条件的一位或多位构成。下表列出了用于指定 events 标志以及测试 revents 标志的一些常值。
该表被分为三个部分:第一部分是处理输入的四个常值,第二部分是处理输出的三个常值,第三部分是处理错误的三个常值。其中第三部分的三个常值不能在 events 中设置,但是当相应条件存在时就在 revents 中返回。
poll 识别三类数据:普通、优先级带(priority band)和高优先级。
就 TCP 和 UDP 套接字而言,以下条件会引起 poll 返回特定的 revents。
(1)所有正规 TCP 数据和所有 UDP 数据都被认为是普通数据。
(2)TCP 的带外数据被认为是优先级带数据。
(3)当 TCP 连接的读半部关闭时(譬如收到了一个来自对端的 FIN),也被认为是普通数据,随后的读操作将返回 0。
(4)TCP 连接存在错误既可以认为是普通数据,也可以认为是错误(POLLERR)。无论哪种情况,随后的读操作将返回 -1,并把 errno 设置成合适的值。这可以用于处理诸如接收到 RST 或发生超时等条件。
(5)在监听套接字上有新的的连接可用既可以认为是普通数据,也可以认为是优先级数据。大多数实现视为普通数据。
(6)非阻塞式 connect 的完成被认为是使相应套接字可写。
结构数组中元素的个数是由参数 nfds 指定的。历史上该参数被定义为无符号长整型,Unix98 为该参数定义了名为 nfds_t 的新的数据类型。
timeout 参数指定 poll 返回前至多等待多长时间,它是一个指定应等待毫秒数的正值。它的可能取值如下:
(1)INFTIM:表示永远等待。POSIX 规范要求在头文件 <poll.h> 中定义 INFTIM,不过许多系统仍然把它定义在 <sys/stropts.h> 中。
(2)0:立即返回,不阻塞进程。
(3)> 0:等待指定数目的毫秒数。
如果不关心某个特定描述符,那么可以把与它对应的 pollfd 结构的 fd 成员设置成一个负数。poll 函数将忽略这样的 pollfd 结构的 events 成员,返回时将它的 revents 成员的值置为 0。
下面是使用 poll 函数实现的一个阻塞式的 TCP 回射服务器。它使用了一个 pollfd 结构的数组来维护客户信息,另外提供了一个 clients 数组来保存连接的客户端描述符,当其中的值为 -1 时表示所在项未使用。
#include <stdio.h> #include <errno.h> #include <poll.h> #include <strings.h> #include <unistd.h> #include <netinet/in.h> #include <sys/socket.h> #ifndef INFTIM #define INFTIM -1 #endif typedef struct sockaddr SA; #define PORT 49877 #define LISTENQ 5 #define MAXLINE 1024 int main(void){ struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); int listenfd = socket(AF_INET, SOCK_STREAM, 0); bind(listenfd, (SA *)&servaddr, sizeof(servaddr)); listen(listenfd, LISTENQ); struct pollfd clients[FOPEN_MAX]; clients[0].fd = listenfd; clients[0].events = POLLRDNORM; int i = 0; for(i=1; i<FOPEN_MAX; i++) clients[i].fd = -1; // -1 indicates available entry int maxi = 0; // max index into clients[] array char buf[MAXLINE]; for(;;){ int nready = poll(clients, maxi+1, INFTIM); if(clients[0].revents & POLLRDNORM){ // new client connection struct sockaddr_in cliaddr; socklen_t clilen = sizeof(cliaddr); int clifd = accept(listenfd, (SA *)&cliaddr, &clilen); // Or: int clifd = accept(listenfd, NULL, NULL); for(i=1; i<FOPEN_MAX; i++){ if(clients[i].fd == -1){ clients[i].fd = clifd; // save descriptor clients[i].events = POLLRDNORM; break; } } if(i == FOPEN_MAX){ printf("too many clients\n"); close(clifd); continue; } if(i > maxi) maxi = i; if(--nready <= 0) // no more readable descriptors continue; } for(i=1; i<=maxi; i++){ // check all clients for data if(clients[i].fd == -1) continue; if(clients[i].revents & (POLLRDNORM | POLLERR)){ ssize_t n; if((n = read(clients[i].fd, buf, MAXLINE)) < 0){ if(errno == ECONNRESET){ //connection reset by client close(clients[i].fd); clients[i].fd = -1; }else{ printf("read error\n"); } }else if(n == 0){ // connection closed by client close(clients[i].fd); clients[i].fd == -1; }else{ write(clients[i].fd, buf, n); } if(--nready <= 0) // no more readable descriptors break; } } } return 0; }
这里检查某个现有连接的返回事件包含 POLLERR 的原因在于:有些实现在一个连接上接收到 RST 时返回的是 POLLERR 事件,而其他的返回的只是 POLLRDNORM 事件。不论哪一种情绪,这里都调用 read。当有错误发生时,read 将返回这个错误。
发表评论
-
Unix 域套接字与描述符的传递
2019-03-27 23:59 709在Unix 域套接字概述一节中介绍了什么是 U ... -
Unix 域套接字概述
2019-03-12 22:48 975Unix 域协议并不是一个实际的协议族,而是在 ... -
kqueue 接口
2019-03-06 00:47 683kqueue 接口是 ... -
辅助数据
2019-02-28 00:40 683辅助数据(a ... -
recv/send 和 recvmsg/sendmsg 函数
2019-01-22 00:40 1535recv 和 send ... -
inetd 守护进程介绍
2019-01-09 21:51 1044在 4.3 BSD 系统之前,很多网络服务都是 ... -
主机名与 IP 地址的转换(续)
2018-12-25 00:37 953在主机名与 IP 地址的转换一节中提到的 ge ... -
主机名与 IP 地址的转换
2018-11-14 00:20 2297在网络编程中,尽管大部分情况下操作的都是 IP ... -
SCTP 事件通知
2018-02-08 03:49 973SCTP 提供了多种可用的通知,用户可经由这些通知追踪 ... -
SCTP 套接字选项
2018-02-04 09:35 1682在获取和设置套接 ... -
SCTP 套接字编程基础函数
2018-02-04 10:08 1048SCTP 服务器可以使 ... -
SCTP 套接字编程基础概念
2018-01-18 00:10 558SCTP 套接字分为一到一套接字和一到多套接字。提供一 ... -
UDP套接字编程基础
2018-01-14 10:37 570下图显示了使用 UDP 套接字编写客户/服务器程序时的 ... -
通用套接字选项
2018-01-02 00:46 544在获取和设置套接 ... -
获取和设置套接字选项
2017-12-29 08:21 434下面几种方法可用 ... -
I/O 复用之select 函数
2017-12-12 00:32 514select 函数允许进 ... -
Unix 5 种 IO 模型概述
2017-11-19 01:44 304Unix 下有 5 种可用 ... -
套接字创建、连接和关闭函数
2017-08-13 17:16 661下图是一对 TCP 客户与服务器进程之间发生的一些典型 ... -
字节转换和填充函数
2017-08-06 01:09 426网络编程中,为保证发送协议栈和接收协议栈就如 32 位 ... -
IPv4 和 IPv6 的套接字地址结构
2017-08-01 21:03 735大多数套接字函数 ...
相关推荐
3. 调用I/O复用函数(如`select`、`poll`或`epoll_wait`)进入等待状态,直到至少有一个文件描述符准备好进行I/O操作。 4. 检查返回的文件描述符集合,对每个就绪的描述符执行相应的读写操作。 5. 根据需要更新文件...
这时,I/O复用模型(如select、poll或epoll)就显得尤为重要。 3. **I/O复用**: - **select**:允许程序监视多个描述符,当其中任一描述符就绪(可读、可写或出现错误),select函数会返回,然后程序可以决定如何...
Windows下的I/O复用主要通过`select`或`poll`函数实现。这些函数允许一个进程监视多个描述符,等待任意一个就绪,而不会阻塞。这种方式提高了程序的并发性。 4. **信号驱动I/O(Signal-Driven I/O)** 这种模型中...
在这个“IO多路复用之poll实例”中,我们将探讨`poll`函数的工作原理、如何使用它以及它在Ubuntu操作系统上与Qt框架的结合应用。 首先,`poll`函数是一个系统调用,它允许我们监视一组文件描述符,查看哪些已经准备...
在进行"Unix网络编程 第6章 I/O复用:select和poll函数"的代码练习时,你可能会涉及到以下内容: 1. 创建并初始化`fd_set`或`pollfd`结构。 2. 使用`FD_SET()`或`pollfd`结构添加文件描述符。 3. 设置合适的超时时间...
Unix系统提供了多种I/O模型,如阻塞I/O、非阻塞I/O、I/O多路复用(如select、poll、epoll)、信号驱动I/O以及异步I/O。I/O聚集通常指的是在一个系统调用中处理多个文件描述符,而I/O分离则是在不同时间或通过不同...
- `select`函数是最早的多路复用I/O机制,它可以监视多个文件描述符,等待它们中的任意一个就绪。当有活动发生时,`select`返回就绪的描述符集合。 - 在客户端和服务端代码中,`select`通常用于同时监听多个Socket...
在I/O复用模型中,程序使用如select、poll或epoll这样的系统调用,它们可以同时监控多个文件描述符(包括套接字),当某个描述符准备就绪时,这些系统调用会返回,然后程序再进行相应的处理,而不是让每个线程各自...
此外,还有多路复用I/O模型,如 select、poll 和 epoll,它们允许单个线程监视多个文件描述符,当其中任何一个描述符就绪时,系统会通知程序。这种方式特别适用于需要同时处理多个连接的服务器应用。 在编写设备...
本文将深入探讨五种主要的套接字I/O模型:阻塞I/O、非阻塞I/O、I/O复用(select/poll/epoll)、信号驱动I/O以及异步I/O,同时通过提供的源代码文件,我们可以更直观地理解这些模型的工作原理。 1. **阻塞I/O模型**...
3. **I/O多路复用**:WINSOCK提供了`select()`和`poll()`函数来实现I/O多路复用。它们允许程序同时监视多个套接字,一旦有数据可读或可写,就通知程序。这对于群聊服务器特别有用,因为它可以高效地处理大量并发连接...
C语言的I/O复用通常涉及以下关键函数: - **select()**:用于监控文件描述符集合,直到某个描述符就绪或超时。 - **poll()**:与select类似,但提供了更灵活的结构来管理文件描述符。 - **epoll_create()**:创建一...
3. I/O复用模型(如select、poll、epoll):允许单个线程监视多个文件描述符,等待数据就绪后再进行读写。 4. 信号驱动I/O模型:在此模型中,当数据准备好时,系统会发送一个信号通知进程。 5. 异步非阻塞I/O模型...
3. **I/O复用模型**:通过`select`或`poll`函数,进程可以在一组套接字上进行轮询,而不是在一个特定的I/O系统调用上阻塞。当有数据就绪时,这些函数会唤醒进程,然后进行实际的数据拷贝。 4. **信号驱动I/O模型...
传统的I/O模型通常分为阻塞I/O、非阻塞I/O、I/O复用(如select、poll、epoll)、信号驱动I/O和异步I/O。重叠IO模型属于异步I/O的一种,但与标准的异步I/O(如POSIX的aio_*函数)不同,它在Windows操作系统中被广泛...
7. **性能优化**:在实际应用中,可能会对模拟I/O进行优化,如使用缓冲技术减少频繁的系统调用,或者利用非阻塞I/O或多路复用I/O(如select、poll、epoll等)提高并发处理能力。 8. **跨平台性**:普通I/O接口在...
多路复用I/O模型,如select和poll函数,可以让单个线程管理多个Socket。它们提供了一种机制,用于检测多个Socket的状态,当有数据可读或可写时,再进行相应操作。虽然提高了并发处理能力,但当Socket数量巨大时,...
在服务器端,我们通常会使用非阻塞I/O模式,避免在等待数据时被阻塞。结合Epoll的边缘触发(EPOLLET)或水平触发(EPOLLONESHOT)模式,可以进一步优化性能。边缘触发意味着只有在事件发生后且未被处理时才会再次...
3. **I/O复用模型(如select、poll、epoll)** I/O复用模型允许单个进程监控多个文件描述符,等待数据就绪后再进行读写。epoll是Linux特有的高性能I/O复用机制,它使用“水平触发”和“边缘触发”两种模式,可以更...