解决在epoll中accept接收端口会漏处理的问题. 直到新的socket消息到达,epoll_wait才响应去接收socket端口数据的问题

本文探讨了在使用epoll时遇到的accept接收端口处理遗漏问题,即在没有新socket消息到达时,epoll_wait不会响应接收端口数据。针对此问题,文章分析原因并提供了解决方案。
摘要由CSDN通过智能技术生成
在用epoll的边缘触发模式中,发现socket接收有异常,有时会出现新的socket连接到底,但是需要有新的数据到底时,epoll_wait才响应去接收数据这个问题。

原因分析:
epoll的边缘触发模式下,同一端口可读时,epoll_wait只会提示一次。在accept中,当2个端口同时到达时,只会响应一次。这时就要用 while等循环函数去接收消息和接收accept响应,一般接收消息大家都会做,接收accept响应会忘。

代码修改:

老代码:

    INT32 conn_fd = accept( listen_fd, (sockaddr *)&clientaddr, &clilen );//accept4( event_fd, (sockaddr *)&clientaddr, &clilen, SOCK_NONBLOCK )
    if( conn_fd < 0 ) {
        MS_LOGER_FATAL("%s%s%s%s", LOG_CMD_FLAG , LOG_VOD_FLAG , "accept error" , strerror( errno ));
    } else {
        MS_LOGER_DEBUG("%s%s%s%d", LOG_CMD_FLAG , LOG_VOD_FLAG , "conn fd" , conn_fd);
    }


新代码:

                
Socket epoll是Linux的网络I/O模型之一,它是一种高效的I/O多路复用机制,能够同时监听多个文件描述符,当其任意一个文件描述符发生事件时,就能够通知应用程序进行相应的处理。 实现epoll的基本步骤如下: 1. 创建一个epoll实例,使用epoll_create函数。 2. 向epoll实例添加监听事件,使用epoll_ctl函数。 3. 调用epoll_wait函数等待事件的发生,如果有事件发生,则返回就绪的文件描述符列表。 4. 根据就绪的文件描述符进行相应的处理。 下面是一个简单的示例代码,实现了一个简单的TCP服务器,使用epoll监听多个连接: #include <sys/epoll.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define MAX_EVENTS 10 #define BUFFER_SIZE 1024 int setnonblocking(int fd) { int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { return -1; } flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { return -1; } return 0; } int main() { int server_fd, client_fd, epoll_fd, nfds, n, i; struct sockaddr_in server_addr, client_addr; socklen_t client_len; char buffer[BUFFER_SIZE]; struct epoll_event ev, events[MAX_EVENTS]; // 创建socket server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("socket"); exit(1); } // 设置socket为非阻塞模式 if (setnonblocking(server_fd) < 0) { perror("setnonblocking"); exit(1); } // 绑定地址和端口 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(12345); if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind"); exit(1); } // 开始监听 if (listen(server_fd, SOMAXCONN) < 0) { perror("listen"); exit(1); } // 创建epoll实例 epoll_fd = epoll_create1(0); if (epoll_fd < 0) { perror("epoll_create1"); exit(1); } // 添加server_fd到epoll实例 ev.events = EPOLLIN; ev.data.fd = server_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0) { perror("epoll_ctl"); exit(1); } while (1) { // 等待事件的发生 nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds < 0) { perror("epoll_wait"); exit(1); } // 处理就绪的文件描述符 for (i = 0; i < nfds; i++) { if (events[i].data.fd == server_fd) { // 有的连接请求 client_len = sizeof(client_addr); client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); if (client_fd < 0) { perror("accept"); continue; } // 设置client_fd为非阻塞模式 if (setnonblocking(client_fd) < 0) { perror("setnonblocking"); exit(1); } // 添加client_fd到epoll实例 ev.events = EPOLLIN | EPOLLET; ev.data.fd = client_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) { perror("epoll_ctl"); exit(1); } } else { // 有数据可读 memset(buffer, 0, BUFFER_SIZE); while ((n = read(events[i].data.fd, buffer, BUFFER_SIZE)) > 0) { printf("Received %d bytes: %s\n", n, buffer); } if (n < 0 && errno != EAGAIN) { perror("read"); exit(1); } // 关闭连接 if (n == 0) { if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL) < 0) { perror("epoll_ctl"); exit(1); } close(events[i].data.fd); } } } } return 0; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值