epoll中accept的使用细节

accept 要考虑 2 个问题
(1) 阻塞模式 accept 存在的问题
考虑这种情况:TCP连接被客户端夭折,即在服务器调用accept之前,客户端主动发送RST终止连接,导致刚刚建立的连接从就绪队列中移出,如果套接口被设置成阻塞模式,服务器就会一直阻塞在accept调用上,
直到其他某个客户建立一个新的连接为止。但是在此期间,服务器单纯地阻塞在accept调用上,就绪队列中的其他描述符都得不到处理。

解决办法: 把监听套接口设置为非阻塞,当客户在服务器调用accept之前中止某个连接时,accept调用可以立即返回-1,这时源自Berkeley的实现会在内核中处理该事件,并不会将该事件通知给epoll,而其他实现把errno设置为ECONNABORTED或者EPROTO错误,我们应该忽略这两个错误。

(2)ET模式下accept存在的问题
考虑这种情况:多个连接同时到达,服务器的TCP就绪队列瞬间积累多个就绪连接,由于是边缘触发模式,epoll只会通知一次,accept只处理一个连接,导致TCP就绪队列中剩下的连接都得不到处理。

解决办法: 用while循环抱住accept调用,处理完TCP就绪队列中的所有连接后再退出循环。如何知道是否处理完就绪队列中的所有连接呢?accept返回-1并且errno设置为EAGAIN就表示所有连接都处理完。综合以上两种情况,服务器应该使用非阻塞地accept,accept在ET模式下的正确使用方式为:

while ((conn_sock = accept(listenfd,(struct sockaddr *) &remote, (size_t *)&addrlen)) > 0) {
    handle_client(conn_sock);
}
if (conn_sock == -1) {
    if (errno != EAGAIN && errno != ECONNABORTED && errno != EPROTO && errno != EINTR)
            perror("accept");
}

另附: https://stackoverflow.com/questions/46086680/why-not-the-accept-system-call-get-all-connected-in-noblock-epoll-lt

### 回答1: 这是一个使用 epoll 实现 Proactor 模式的简单示例: ``` #include <sys/epoll.h> #include <unistd.h> #include <string.h> #define MAX_EVENTS 10 int main() { int epoll_fd = epoll_create1(0); if (epoll_fd == -1) { // handle error } // 添加要监听的文件描述符 struct epoll_event event; event.events = EPOLLIN; event.data.fd = STDIN_FILENO; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, STDIN_FILENO, &event) == -1) { // handle error } // 使用 epoll_wait 循环等待事件 struct epoll_event events[MAX_EVENTS]; while (true) { int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds == -1) { // handle error } // 处理已就绪的事件 for (int i = 0; i < nfds; i++) { if (events[i].events & EPOLLIN) { char buffer[1024]; ssize_t bytes_read = read(events[i].data.fd, buffer, sizeof(buffer)); if (bytes_read == -1) { // handle error } else if (bytes_read == 0) { // EOF } else { // 处理读到的数据 } } else { // 处理其他事件 } } } close(epoll_fd); return 0; } ``` 这个程序使用 epoll 创建一个新的 epoll 实例并添加要监听的文件描述符(在这个示例是标准输入)。然后,它使用 epoll_wait 循环等待事件的发生。当事件发生时,它会处理已就绪的事件。 注意:这个示例只是简单地监听标准输入并读取数据,但 Proactor 模式通常用于实现高性能的异 ### 回答2: Proactor模式是一种基于事件驱动的并发模式,常用于高性能的异步编程。而epoll是Linux操作系统提供的一种事件驱动的I/O多路复用机制。 下面以一个简单的示例来说明如何使用epoll实现Proactor模式: 1. 首先创建一个epoll实例,并注册感兴趣的事件。例如,我们要监听一个TCP服务器的连接请求,可以将服务器的监听socket注册为读事件。 2. 当有新的连接请求到达时,epoll会通知应用程序。应用程序可以通过accept函数接收并处理连接请求。 3. 接下来,我们将接收到的连接socket也注册到epoll实例,并关注读事件。这样,在有数据可读时,epoll会通知应用程序。 4. 当epoll通知应用程序有数据可读时,应用程序可以通过recv函数读取数据,并进行相应的处理。 5. 如果应用程序需要向客户端发送数据,可以通过send函数发送数据。发送时,可以不阻塞。这可以通过设置连接socket为非阻塞模式来实现。 6. 当存在多个连接请求时,epoll会自动处理多个事件,从而提高并发性能。此时,应用程序可以通过异步方式处理所有的连接和数据传输。 通过将epollProactor模式结合使用,我们可以实现高性能的异步编程。通过单线程处理多个连接和事件,可以避免多线程的开销和复杂性,并提高应用程序的并发处理能力。 需要注意的是,以上只是一个简单的示例,实际的应用可能涉及更多的细节和处理逻辑。但是通过epollProactor模式的结合,我们可以更好地利用系统资源,提高处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值