epoll 监听 fd 关闭
时间: 2023-10-28 13:49:11 浏览: 366
在使用 epoll 进行事件轮询时,当监听的文件描述符(fd)被关闭时,需要进行一定的处理。
一种方法是在每次调用 epoll_wait() 时检查每个返回的事件是否出错,如果出错了,则可以认为对应的文件描述符已经关闭了。但这种方法会导致额外的系统调用和 CPU 开销。
另一种方法是使用 EPOLLHUP 和 EPOLLERR 事件来处理关闭的文件描述符。当监听的文件描述符被关闭时,内核会向应用程序发送一个 EPOLLHUP 事件。如果出现错误,则会发送一个 EPOLLERR 事件。应用程序可以通过检查这些事件来进行相应的处理。
当接收到 EPOLLHUP 或 EPOLLERR 事件时,应用程序应该关闭对应的文件描述符,并从 epoll 实例中删除该文件描述符。如果不删除,下一次调用 epoll_wait() 时会返回一个 EPOLLHUP 或 EPOLLERR 事件,导致额外的系统调用和 CPU 开销。
相关问题
EPOLL 监听 UDP 代码示例
下面是一个简单的用 EPOLL 监听 UDP 的代码示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_EVENTS 10
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket error");
exit(1);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8888);
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind error");
exit(1);
}
int epollfd = epoll_create(1);
if (epollfd == -1) {
perror("epoll_create error");
exit(1);
}
struct epoll_event ev, events[MAX_EVENTS];
ev.events = EPOLLIN;
ev.data.fd = sockfd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
perror("epoll_ctl error");
exit(1);
}
while (1) {
int n = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (n == -1) {
perror("epoll_wait error");
exit(1);
}
for (int i = 0; i < n; i++) {
if (events[i].data.fd == sockfd) {
struct sockaddr_in cli_addr;
socklen_t len = sizeof(cli_addr);
char buf[1024];
int nrecv = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&cli_addr, &len);
if (nrecv == -1) {
perror("recvfrom error");
exit(1);
}
buf[nrecv] = '\0';
printf("Received %d bytes from %s:%d: %s\n", nrecv, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buf);
}
}
}
close(epollfd);
close(sockfd);
return 0;
}
```
在上面的代码中,我们先创建了一个 UDP 套接字,并绑定到本地地址和端口上。然后创建了一个 EPOLL 对象,并将监听套接字注册到其中,并设置事件类型为 EPOLLIN,表示可以读取数据。最后在 while 循环中不断调用 epoll_wait 等待事件发生,并在事件发生时进行处理(在这里只处理了来自监听套接字的数据)。
UDP 怎么使用EPOLL 监听接收
使用EPOLL监听UDP接收需要以下步骤:
1. 创建UDP套接字并绑定端口号
2. 创建epoll实例,将UDP套接字添加到epoll实例中
3. 调用epoll_wait()函数进行监听事件
4. 如果epoll_wait()返回UDP套接字有事件发生,则调用recvfrom()函数接收UDP数据包
以下是一个简单的示例代码:
```
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_EVENTS 10
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
int epfd = epoll_create(MAX_EVENTS);
struct epoll_event event, events[MAX_EVENTS];
event.data.fd = sockfd;
event.events = EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
while (1) {
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) {
if (events[i].data.fd == sockfd) {
char buffer[1024];
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_len);
printf("Received %d bytes from %s:%d\n", len, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
}
}
}
close(epfd);
close(sockfd);
return 0;
}
```
在这个示例代码中,我们创建了一个UDP套接字,并绑定了端口号8080。然后,我们创建了一个epoll实例,并将UDP套接字添加到epoll实例中。在主循环中,我们调用epoll_wait()函数进行监听事件,如果UDP套接字有事件发生(EPOLLIN),则调用recvfrom()函数接收UDP数据包。
阅读全文