gpt4 book ai didi

c - 在epoll上看到两个accept事件

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:45:16 31 4
gpt4 key购买 nike

我第一次在 Linux 上玩 epoll,看到了一些奇怪的行为。具体来说,当我将客户端连接到套接字时,我看到服务器端的 epoll_wait 发出了两个事件。当我第二次尝试调用 accept 时,出现“暂时不可用”错误。

这是简单的客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

const char* msg = "friendly ping";

int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <socket>\n", argv[0]);
exit(-1);
}

int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(-1);
}

struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);

if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("Error connecting");
exit(-1);
}

write(sock, msg, strlen(msg));
close(sock);

return 0;
}

服务器代码如下:

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

const int kMaxEvents = 100;
const char *kSocketFile = "dummy_socket";

void MakeNonBlocking(int fd) {
int flags, s;

flags = fcntl (fd, F_GETFL, 0);
if (flags == -1) {
perror ("fcntl");
exit(-1);
}

flags |= O_NONBLOCK;
s = fcntl (fd, F_SETFL, flags);
if (s == -1) {
perror ("fcntl");
exit(-1);
}
}

void AcceptConnections(int sock, int epoll_fd) {
struct epoll_event event;
event.data.fd = sock;
event.events = EPOLLIN;

int insock = accept(sock, NULL, NULL);
if (insock < 0) {
perror("Error accepting connection");
exit(-1);
}

MakeNonBlocking(insock);

int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event);
if (s < 0) {
perror("Epoll error adding accepted connection");
exit(-1);
}
printf("Connection processed.\n");
}

int main(void) {
int sock, efd, n;
struct sockaddr_un addr;
struct epoll_event event;
struct epoll_event *events;
char buf[1024];

if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("Error creating socket.");
exit(-1);
}

addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, kSocketFile, sizeof(addr.sun_path) - 1);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("Error binding name to socket");
exit(-1);
}

if (listen(sock, SOMAXCONN) < 0) {
perror("Error listening on socket");
exit(-1);
}

MakeNonBlocking(sock);

if ((efd = epoll_create1(0)) < 0) {
perror("Epoll initialization error");
exit(-1);
}

event.data.fd = sock;
event.events = EPOLLIN;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &event) < 0) {
perror("Epoll error adding socket");
exit(-1);
}

events = (struct epoll_event*) calloc(kMaxEvents, sizeof(event));
if (!events) {
perror("Error allocating event buffers");
exit(-1);
}

while(1) {
printf("Calling epoll_wait\n");
if ((n = epoll_wait(efd, events, kMaxEvents, -1)) == -1) {
perror("epoll_wait failure");
exit(-1);
}

for (int i = 0; i < n; ++i) {
printf("Checking event for fd = %d\n", events[i].data.fd);
if (sock == events[i].data.fd) {
AcceptConnections(sock, efd);
continue;
}

int count = read(events[i].data.fd, buf, 100);
if (count == 0) {
close(events[i].data.fd);
}
write(1, buf, count);
}
}

free(events);
close(efd);
close(sock);
unlink(kSocketFile);
return 0;
}

当我运行服务器并连接到客户端时,我得到:

Calling epoll_wait
Checking event for fd = 3
Connection processed.
Calling epoll_wait
Checking event for fd = 3
Error accepting connection: Resource temporarily unavailable

换句话说,我在监听套接字上看到了两个事件。有什么想法吗?

最佳答案

要修复,请将 AcceptConnections 更改为:

void AcceptConnections(int sock, int epoll_fd) {
struct epoll_event event;
event.events = EPOLLIN;

int insock = accept(sock, NULL, NULL);
if (insock < 0) {
perror("Error accepting connection");
exit(-1);
}

// This is the important change.
event.data.fd = insock;

MakeNonBlocking(insock);

int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event);
if (s < 0) {
perror("Epoll error adding accepted connection");
exit(-1);
}
printf("Connection processed.\n");
}

epoll 有时很有趣...

问题在于您在 AcceptConnections 中注册事件的方式。

epoll接受两个不同的fd值,一个在event.data.fd(用户不透明数据值)中,另一个在开头epoll_ctl 函数调用(fd 控制事件)。

event.data.fd 可以是任何东西,它是您在事件循环中读取的实际数据...

...在您的原始代码中,您将其设置为 listening 套接字而不是 client 套接字。

因此,当 client 套接字准备好读取数据时,将引发一个事件,其中 event.data.fd 指向 listening 套接字而不是客户端 套接字。

由于您没有清除事件(对于客户端套接字),它会使用您设置的数据(监听套接字 fd)反复引发。

祝你好运!

关于c - 在epoll上看到两个accept事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37910657/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com