Linux Poll机制实战演示教程

linux poll demo

时间:2024-12-09 18:26


Linux Poll Demo:高效I/O事件处理的典范 在现代操作系统中,高效地处理I/O事件是构建高性能应用程序的关键

    Linux操作系统以其强大的内核功能和丰富的系统调用接口,为开发者提供了多种处理I/O事件的方法

    其中,`poll`系统调用作为一种灵活且高效的机制,在处理多个文件描述符(file descriptors, FDs)的I/O事件时表现尤为突出

    本文将通过一个详细的`linux polldemo`,展示如何使用`poll`系统调用来实现高效的I/O事件处理,并深入探讨其背后的原理与优势

     一、`poll`系统调用简介 `poll`是POSIX标准定义的一个系统调用,用于监视多个文件描述符上的I/O事件

    与`select`系统调用相比,`poll`提供了更丰富的功能集,能够处理更多类型的文件描述符(如管道、套接字、终端设备等),并且对每个文件描述符可以指定多种感兴趣的事件类型(如读就绪、写就绪、异常条件等)

     `poll`函数原型如下: include int poll(struct pollfdfds, nfds_t nfds, int timeout); - `fds`:指向`pollfd`结构体数组的指针,每个`pollfd`结构体代表一个要监视的文件描述符及其感兴趣的事件

     - `nfds`:`fds`数组中的元素数量,即要监视的文件描述符总数

     - `timeout`:等待事件的超时时间(毫秒)

    -1表示无限等待,0表示立即返回,不阻塞

     `pollfd`结构体定义如下: struct pollfd { int fd; // 文件描述符 short events; // 感兴趣的事件类型 short revents; // 实际发生的事件类型(由`poll`返回时填充) }; 二、`linux polldemo`实现 下面,我们通过一个具体的示例来展示如何使用`poll`系统调用来处理多个文件描述符上的I/O事件

    这个示例将创建一个服务器,它同时监听一个TCP套接字和一个标准输入(用于接收用户命令),以展示`poll`在处理并发I/O事件时的能力

     2.1 示例代码 include include include include include include define PORT 8080 defineBUFFER_SIZE 1024 void error_handling(constchar message) { perror(message); exit(EXIT_FAILURE); } int main() { intserver_sock,client_sock; structsockaddr_in server_addr, client_addr; socklen_tclient_addr_size; struct pollfdfds【2】; charbuffer【BUFFER_SIZE】; ssize_tstr_len; // 创建TCP套接字 if((server_sock = socket(PF_INET, SOCK_STREAM, 0)) == - error_handling(socket() error); // 设置服务器地址信息 memset(&server_addr, 0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(PORT); // 绑定套接字到指定端口 if(bind(server_sock, (struct sockaddr)&server_addr, sizeof(server_addr)) == -1) error_handling(bind() error); // 监听连接请求 if(listen(server_sock, == - error_handling(listen() error); // 初始化pollfd数组 fds【0】.fd = server_sock; fds【0】.events = POLLIN; // 对server_sock感兴趣的事件是读就绪(即有新连接) fds【0】.revents = 0; fds【1】.fd = STDIN_FILENO; // 标准输入文件描述符 fds【1】.events = POLLIN; // 对标准输入感兴趣的事件也是读就绪 fds【1】.revents = 0; printf(Server is listening on port %d... , PORT); printf(Press q to quit.n); while(1) { int ret =poll(fds, 2, -1); // 无限等待,直到有事件发生 if(ret == - error_handling(poll() error); // 检查server_sock是否有新连接 if(fds【0】.revents & POLLIN) { client_addr_size = sizeof(client_addr); client_sock = accept(server_sock, (struct sockaddr)&client_addr, &client_addr_size); if(client_sock == - error_handling(accept() error); printf(New client connected: %s:%dn,inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 这里可以添加代码将client_sock加入到一个新的pollfd数组中,以便单独处理每个客户端的I/O事件 // 为简化示例,这里仅打印消息,不处理客户端数据 } // 检查标准输入是否有数据可读 if(fds【1】.revents & POLLIN) { str_len = read(STDIN_FILENO, buffer, BUFFER_SIZE - 1); if(str_len == - error_handling(read() error); buffer【str_len】 = 0; // 确保字符串以null结尾 if(strncmp(buffer, q, 1) == 0) { printf(Exiting... ); break; } printf(You entered: %s , buffer); } } // 关闭套接字 close(server_sock); return 0; } 2.2 代码解析 1.创建TCP套接字并绑定端口: -使用`socket()`创建TCP套接字

     -使用`bind()`将套接字绑定到指定端口

     -使用`listen()`开始监听连接请求

     2.初始化pollfd数组: -`fds【0】`用于监视服务器套接字(`server_sock`),感兴趣的事件是读就绪(`POLLIN`)

     -`fds【1】`用于监视标准输入(`STDIN_FILENO`),同样感兴趣的事件是读就绪(`POLLIN`)

     3.进入事件循环: -使用`poll()`等待事件发生

    `po