如果我这样做(以下伪代码)会发生什么:插座的正确顺序要求预分叉服务器
s = socket
bind s
fork ....
(... at child ...)
listen s
conn = accept s
?我应该改用:
s = socket
bind s
listen s
fork ....
conn = accept s
?
哪一个是正确的?另外,我是否需要在套接字上为这个特定场景设置任何选项?
如果我这样做(以下伪代码)会发生什么:插座的正确顺序要求预分叉服务器
s = socket
bind s
fork ....
(... at child ...)
listen s
conn = accept s
?我应该改用:
s = socket
bind s
listen s
fork ....
conn = accept s
?
哪一个是正确的?另外,我是否需要在套接字上为这个特定场景设置任何选项?
哪一项是正确[,呼吁
listen()
之前或之后fork()
]?
调用listen()
前fork()
是正确的。 listen()
的作用是将底层套接字标记为准备好与连接待办事项进行连接。它只需要调用一次。
从代码质量的角度来看,我会将另一种方法标记为“不正确”,因为它是多余的和令人困惑的。
虽然反复调用listen()
并没有害处,但它很可疑。该规范没有说明在进行后续调用时会发生什么情况,只是面向连接的套接字应该是"maintain a queue of outstanding connection indications",也就是未决连接的积压。随后的调用是否能够改变积压的大小?你想要它?事实上,并非所有的操作系统甚至可以让你查询积压的大小(FreeBSD有,例如,SO_LISTENQLIMIT)。
在Linux(因为3.9)(和Mac OS和FreeBSD可能还有其他人),你也可以选择使用SO_REUSEPORT
的选项。
// _DEFAULT_SOURCE for htobe16 for the port number, you may need _BSD_SOURCE instead
#define _DEFAULT_SOURCE
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <endian.h>
int main() {
struct sockaddr_in6 sa;
int v = 1;
// prepare ipv6 address [::]:1345
memset(&sa, 0, sizeof(sa));
sa.sin6_family = AF_INET6;
sa.sin6_port = htobe16(1345);
int s = socket(AF_INET6, SOCK_STREAM, 0);
perror("socket");
// the key point: enable SO_REUSEPORT
setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v));
perror("setsockopt");
// from this point on just plain old socket use
bind(s, (struct sockaddr*)&sa, sizeof(sa));
perror("bind");
listen(s, 0);
perror("listen");
while (1) {
int conn = accept(s, NULL, NULL);
perror("accept");
close(conn);
perror("close");
}
return 0;
}
这种方法的优点是在进程之间不需要父/子关系。另外,联机帮助页(setsockopt(7)
)表明,这比传统方法的性能有所提高。
在这种情况下,您可以在之前拨打致电socket
。唯一的要求是,全部涉及进程在其套接字上设置SO_REUSEPORT
并共享相同的有效UID。
这是超酷!它可能无法在Mac OS X中运行,所以我不会为重新启用pre-fork而感到不快,但我一定会在Linux中寻找使用这种方法的方法。 – dsign
请务必检查。 SO_REUSEPORT在登陆时是一件更大的事情,我可以想象BSD和Mac OS也实现了这一点。 –
看到编辑,我发现一个苹果手册页,提示SO_REUSEPORT可用。 –
其实这两个都不正确http://www.tutorialspoint.com/unix_sockets/socket_server_example.htm看最后一个例子。 –
@RomainHippeau谢谢。第二个例子不是前叉,因为我理解它。 – dsign