首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

linux c poll

poll 是 Linux 系统下的一种 I/O 多路复用机制,它允许一个进程监视多个文件描述符,等待这些文件描述符中的任何一个变为可读、可写或发生异常条件。以下是关于 poll 的基础概念、优势、类型、应用场景以及可能遇到的问题和解决方法:

基础概念

poll 函数是 Linux 系统调用,用于监视多个文件描述符的状态。它接受一个 pollfd 结构体数组作为参数,每个 pollfd 结构体包含一个文件描述符、感兴趣的事件以及发生的事件。

优势

  1. 跨平台支持poll 是 POSIX 标准的一部分,因此它在一个支持 POSIX 的系统上可以在不同的线程间通用。
  2. 灵活性:与 select 相比,poll 没有最大文件描述符数量的限制,这使得它在处理大量并发连接时更加高效。
  3. 减少系统调用poll 只需要一次系统调用就可以监视多个文件描述符,而 select 在每次调用时都需要重新初始化文件描述符集合。

类型

poll 主要涉及以下类型:

  • pollfd 结构体:包含文件描述符、感兴趣的事件和发生的事件。
  • POLLIN:表示文件描述符可读。
  • POLLOUT:表示文件描述符可写。
  • POLLERR:表示文件描述符发生错误。
  • POLLHUP:表示文件描述符挂起事件。

应用场景

poll 常用于需要处理大量并发连接的服务器,如 Web 服务器、聊天服务器等。它可以有效地监视多个客户端连接,当任何一个连接有数据可读或可写时,poll 会立即返回。

可能遇到的问题及解决方法

  1. 效率问题:虽然 pollselect 更高效,但在处理大量文件描述符时,仍然可能遇到性能瓶颈。此时,可以考虑使用 epoll(Linux 特有)或 kqueue(BSD 系统)等更高效的 I/O 多路复用机制。
  2. 编程复杂性:使用 poll 需要管理多个文件描述符的状态,这可能会增加编程的复杂性。为了简化编程,可以使用一些高级的网络库,如 Boost.Asio(C++)或 libevent(C/C++),这些库封装了底层的 I/O 多路复用机制,提供了更简洁的 API。
  3. 错误处理:在使用 poll 时,需要注意处理各种可能的错误情况,如文件描述符无效、系统调用被中断等。为了确保程序的健壮性,应该对这些错误情况进行适当的处理。

示例代码(C 语言)

下面是一个简单的 poll 使用示例,该示例创建了一个监听套接字,并使用 poll 来等待客户端连接:

代码语言:txt
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <poll.h>

#define MAX_CLIENTS 10

int main() {
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in server_addr = {0};
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(8080);

    bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    listen(listen_fd, SOMAXCONN);

    struct pollfd fds[MAX_CLIENTS + 1];
    fds[0].fd = listen_fd;
    fds[0].events = POLLIN;
    int nfds = 1;

    while (1) {
        int ret = poll(fds, nfds, -1);
        if (ret < 0) {
            perror("poll");
            exit(1);
        }

        if (fds[0].revents & POLLIN) {
            struct sockaddr_in client_addr = {0};
            socklen_t client_len = sizeof(client_addr);
            int conn_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_len);
            if (conn_fd < 0) {
                perror("accept");
                continue;
            }

            fds[nfds].fd = conn_fd;
            fds[nfds].events = POLLIN;
            nfds++;
        }

        for (int i = 1; i < nfds; i++) {
            if (fds[i].revents & POLLIN) {
                char buf[1024];
                ssize_t n = read(fds[i].fd, buf, sizeof(buf));
                if (n <= 0) {
                    close(fds[i].fd);
                    fds[i] = fds[nfds - 1];
                    nfds--;
                    i--;
                } else {
                    write(fds[i].fd, buf, n); // Echo back
                }
            }
        }
    }

    close(listen_fd);
    return 0;
}

这个示例创建了一个简单的回声服务器,它使用 poll 来等待客户端连接和数据。当有新的客户端连接时,服务器会接受连接并将其添加到 poll 的监视列表中。当客户端发送数据时,服务器会读取数据并将其回显给客户端。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

Linux select poll源码剖析

在读select、poll源码前,需要先了解的知识点: 等待队列 文件系统(主要是进程的打开文件描述符表以及struct file) poll机制 资源注册监听poll() -> poll_wait(...select()/poll()调用对应一个struct poll_wqueues 一个监听事件对应一个struct poll_table_entry Common poll机制是所有多路转接的共性;调用控制块.../* * Structures and helpers for sys_poll/sys_poll */ struct poll_wqueues { poll_table pt; struct...实际linux内核设计: * 每个wait_queue_t的private字段指向同一个poll_wqueues,然后 * 共用的poll_wqueues中保存了指向调用进程...被封装在了poll_wqueues结构体中,以便之后向资源 * 注册监听的时候,能够用poll_table得到对应的poll_wqueues * * 初始化poll_wqueues

3.2K20
  • 【Linux】高级IO --- 多路转接,select,poll,epoll

    而此时走过来一个李四,李四这名少年也很喜欢钓鱼,但李四和张三不一样,李四左口袋装着《Linux高性能服务器编程》,右口袋装着一本《算法导论》,左手拿手机,右手拿了一根鱼竿,李四拿了钓鱼凳坐下之后,李四就开始钓鱼了...在这里额外补充一下,linux命令行中表示输入结束的快捷键是ctrl+d,当此热键被用户按下后,代表0号文件描述符写端关闭,此时读端会读到0,read会返回0值,此时进程除了输出提示信息"read file...虽然说epoll是作了改进的poll,但在接口的使用和底层实现上,epoll和poll天差地别,在linux内核2.5.44版本时,就引入了epoll接口,而现在主流的linux内核版本已经是3点几了。...模型其实也是一个struct file结构体,所以epoll_create创建epoll模型成功后,会返回一个文件描述符,而epoll_create的size参数早在内核版本2.6以后就已经被忽略了,在早期的linux...select优点: (1)能够同时监听多个文件描述符,使得一个进程或线程能够同时管理多个IO操作,提升IO的效率 (2)select 是一个跨平台的系统调用,几乎在所有主流操作系统上都得到支持,包括 Linux

    36330

    Linux中的sleep、usleep、nanosleep、poll和select

    在进行Linux C/C++编程时,可调用的sleep函数有好多个,那么究竟应当调用哪一个了?...不确定 即使被信号中断,也可实现实际睡眠时长不小于参数指定时长 clock_nanosleep 系统调用 纳秒 是 不确定 区别于nanosleep,可选择为相对或绝对时间,其次是可以选择使用哪个时钟 poll...C++常用封装: 1) 基于nanosleep的毫秒级封装 #include void millisleep(uint32_t milliseconds) { struct timespec ts...microseconds % 1000000) * 1000 }; while ((-1 == nanosleep(&ts, &ts)) && (EINTR == errno)); } 3) 基于poll...的秒级封装 // 可libco协程库中安全使用 void pollsleep(int milliseconds) { (void)poll(NULL, 0, milliseconds); } 4)

    5.1K40

    【Linux高级IO】Linux多路转接:深入探索poll与epoll的奥秘

    ❀ Linux高级IO 多路转接:poll poll函数接口 poll优缺点 多路转接:epoll epoll的相关系统调用 epoll工作原理 epoll的优点 epoll工作方式 理解ET模式和非阻塞文件描述符...为了应对这一挑战,Linux操作系统提供了多种I/O多路复用技术,其中poll和epoll作为两种重要的机制,在提升系统资源利用率和处理效率方面发挥着关键作用。...多路转接:poll 在Linux系统中,多路转接技术是一种重要的I/O处理机制,它允许单个线程同时监控多个文件描述符(例如套接字)上的事件,从而有效地管理多个并发连接。...在内核层面,遍历检测,关心的fd是否有对应的事件就绪 poll作为Linux中的多路转接技术之一,在处理多个并发连接时具有一定的优势。...多路转接:epoll epoll是Linux下多路复用I/O接口select/poll的增强版本,旨在提高程序在大量并发连接中只有少量活跃情况下的系统CPU利用率。

    11110

    大话 Select、Poll、Epoll

    遗憾的是,linux的网络IO中是不存在异步IO的,linux的网络IO处理的第二阶段总是阻塞等待数据copy完成的。真正意义上的网络异步IO是Windows下的IOCP(IO完成端口)模型。...2 Linux的socket 事件wakeup callback机制 言归正传,在介绍select、poll、epoll前,有必要说说linux(2.6+)内核的事件wakeup callback机制,...Linux通过socket睡眠队列来管理所有等待socket的某个事件的process,同时通过wakeup机制来异步唤醒整个睡眠队列上等待事件的process,通知process相关事件发生。...在linux 2.6.8之前的内核,epoll使用hash来组织fds集合,于是在创建epoll fd的时候,epoll需要初始化hash的大小。...在linux 2.6.8以后的内核中,epoll使用红黑树来组织监控的fds集合,于是epoll_create(int size)的参数size实际上已经没有意义了。

    26K4921

    select,poll,epoll区别

    select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。...epoll 直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。...实际上,当前版本的Linux会自动修改timeout参数,设置它的值为剩余时间。...在Linux中,这个值是1024。本章后面我们还将看到这个限制的衍生物。 返回值和错误代码 select()成功时返回准备好I/O的文件描述符数目,包括所有三个set。...4.内核微调     这一点其实不算epoll的优点了,而是整个linux平台的优点。也许你可以怀疑linux平台,但是你无法回避linux平台赋予你微调内核的能力。

    1.4K21

    使用 poll 检测管道断开

    一般使用 poll 检测 socket 或标准输入时,只要指定 POLLIN 标志位,就可以检测是否有数据到达,或者连接断开: 1 struct pollfd fds[3]; 2 fds[0].fd...sock_fd; 5 fds[1].events = POLLIN; 6 fds[2].fd = pipe_fd; 7 fds[2].events = POLLIN; 8 ret = poll...一个已经关闭的句柄时(句柄号 >=0 有效),poll 本身并不返回错误,而是给对应的句柄事件中设置  POLLNVAL 标志位: 1 if (pfd[2].revents & POLLNVAL) {...2 // handle pipe close 3 ... 4 } 若 poll 一个无效句柄时(句柄号为-1),poll 本身仍不返回错误,但该句柄一定没有任何事件可供检测与返回...当然如果传入 poll 的句柄数组中所有句柄都为无效句柄时,poll仍不返回错误,此时若提供超时,可当成sleep使用; 若不提供超时,则会进入无限期等待…… 测试代码

    78720
    领券