【发布时间】:2021-12-12 00:42:16
【问题描述】:
for (int t = 0; t < physicalCoreCount; t++) {
int pid = fork();
if (pid==0) {
// setting up epoll
epoll_fd = epoll_create1(0);
event.data.fd = listenSocketfd;
event.events = EPOLLIN | EPOLLET;
ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listenSocketfd, &event);
events = (epoll_event*)calloc(LISTENQ, sizeof(event));
//*****/
while (1) {
int ndfs = epoll_wait(epoll_fd, events, curfdCount, -1);
if (ndfs==-1) {
continue;
}
for (int i=0; i < ndfs; i++) {
if (events[i].data.fd == listenSocketfd) { // original listener
int new_connfd = accept(events[i].data.fd, (sockaddr*)&clientaddr, &clientlen);
if (new_connfd==-1) {
if (errno==EAGAIN || errno==EWOULDBLOCK) {
continue;
}
else exitPerrorLog("accept()");
}
set_non_block(new_connfd);
event.events = EPOLLIN | EPOLLET;
event.data.fd = new_connfd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_connfd, &event) < 0)
exitPerrorLog("epoll_ctl");
clientaddrOfFd[new_connfd] = new sockaddr_in();
memcpy(clientaddrOfFd[new_connfd], &clientaddr, sizeof(clientaddr));
curfdCount++;
}
else {
process(events[i].data.fd, clientaddrOfFd[events[i].data.fd]);
//epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, &event);
if (curfdCount > 10000) curfdCount = 10000; //curfdCount--;
}
}
}
}
}
出现问题是因为我正在尝试实现持久连接(响应后未关闭)。然而,孩子 0 可以接受()一个套接字文件描述符 X,处理它,但后来孩子 1 可以接受()相同的文件描述符。由于我没有关闭子 0 上的连接(以实现 HTTP1.1 keep-alive),现在 2 个子正在读取/写入同一个文件描述符。
有什么方法可以防止这个问题?谢谢。
编辑: 重要更新:所以主要问题是我认为 2 个相同的 FD 意味着它是相同的连接,我想避免这种情况,因为它会导致 2 个孩子读/写相同的东西.如果这种情况没有发生(读/写重叠),那么我认为问题已经解决。有人可以确认吗?
【问题讨论】:
-
只有一个进程可以接受特定的连接。
-
两个子进程可能会从
accept得到相同的fd返回值,但它们应该是不同的连接。使用getsockname检查每个孩子连接的客户端地址和端口号。 -
@IanAbbott 哦,我认为同一个 FD 意味着它是同一个客户端
-
@IanAbbott 但如果它确实来自同一个客户端,那么让 2 个子进程接受 2 个连接的性能是否比只接受一次的性能低?我希望重用(已建立的)连接
-
“我认为同一个 FD 意味着它是同一个客户端”——每个子节点在分叉之后都有相同的一组正在使用的文件描述符(因为父节点之间没有关闭或打开更多的文件描述符) forks),因此每个子节点的最低未使用文件描述符将是相同的。
accept()调用将返回最低的未使用文件描述符,这对于每个孩子都是相同的。
标签: c sockets fork epoll persistent-connection