【发布时间】:2021-02-12 08:12:33
【问题描述】:
struct sockaddr_in srv;
fd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, ...);
srv.sin_family = AF_INET;
srv.sin_addr.s_addr = INADDR_ANY;
srv.sin_port = htons(9900);
bind(fd, (const struct sockaddr *)&srv, sizeof srv);
for (i = 0; i < MAX_PROCS; i++) {
pid = fork();
if (pid == 0) {
/* child context */
listen(fd, MAXCONN);
connfd = accept(fd, NULL, NULL);
...
close(connfd);
} else
}
为简洁起见,我删除了错误检查和其他部分。此代码有效,我可以在 localhost:9900 上 telnet 并查看连接。不过
% lsof -i :9900
报告所有 LISTEN 连接都属于具有相同 inode 的套接字,这认为这是有道理的,因为套接字在父节点中创建一次,并且每个子节点都共享它。
所以我想如果我想在同一个address:port 元组上真正有多个听众,我应该对每个孩子执行 bind() - listen() 序列。对吗?
但是这会导致错误:bind() 返回 EINVAL,我只创建了一个孩子:
for (i = 0; i < MAX_PROCS; i++) {
pid = fork();
if (pid == 0) {
srv.sin_family = AF_INET;
srv.sin_addr.s_addr = INADDR_ANY;
srv.sin_port = htons(9900);
bind(fd, (const struct sockaddr *)&srv, sizeof srv);
...
listen();
accept();
}
}
我做错了什么?
【问题讨论】:
-
检查返回值和errno。第二个(以及后续)可能因 EADDRINUSE 而失败
-
@wildplasser。谢谢你的答复。所以 SO_REUSEPORT 选项不够用?
-
@wildplasser。可能是我不清楚——bind() 为循环中的所有人返回 EINVAL,除了第一个。
-
只检查返回值。这是有原因的。
-
@wildplasser,正如我之前写的,返回值为 EINVAL。