Linux 预分叉服务器的套接字调用顺序正确

Linux 预分叉服务器的套接字调用顺序正确,linux,sockets,posix,Linux,Sockets,Posix,如果我这样做会发生什么(下面的伪代码): ??我是否应该使用: s = socket bind s listen s fork .... conn = accept s ? 哪一个是正确的?此外,我是否需要为此特定场景在套接字上设置任何选项 哪一个是正确的[,在fork()]之前或之后调用listen() 在fork()之前调用listen()是正确的。listen()的作用是将底层套接字标记为已准备好使用连接积压进行连接。它只需要调用一次 从代码质量的角度来看,我认为另一种方

如果我这样做会发生什么(下面的伪代码):

??我是否应该使用:

s = socket 
bind s 
listen s 
fork .... 
   conn = accept s 
?

哪一个是正确的?此外,我是否需要为此特定场景在套接字上设置任何选项

哪一个是正确的[,在
fork()
]之前或之后调用
listen()

fork()
之前调用
listen()
是正确的。
listen()
的作用是将底层套接字标记为已准备好使用连接积压进行连接。它只需要调用一次

从代码质量的角度来看,我认为另一种方法是“不正确的”,因为它是多余的和令人困惑的

虽然反复调用
listen()
并没有什么害处,但这是相当可疑的。该规范没有说明在进行后续调用时会发生什么,只是说明面向连接的套接字应该是一个待处理连接的积压。后续调用是否能够更改待办事项的大小?你愿意吗?事实上,并不是所有的操作系统都允许您查询积压工作的大小(例如FreeBSD有)。

在Linux上(从3.9开始)(以及其他可能的操作系统),您还可以选择使用
SO\u REUSEPORT

/\u htobe16的默认\u源对于端口号,您可能需要\u BSD\u源
#定义\u默认\u源
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(){
结构sockaddr_in 6 sa;
int v=1;
//准备ipv6地址[:]:1345
memset(&sa,0,sizeof(sa));
sa.sin6_family=AF_INET6;
sa.sin6_端口=htobe16(1345);
int s=套接字(AF_INET6,SOCK_流,0);
佩罗(“插座”);
//关键点:启用SO_重用端口
setsockopt(s,SOL_SOCKET,SO_REUSEPORT,&v,sizeof(v));
perror(“setsockopt”);
//从这一点上来说,只是简单的旧套接字使用
绑定(s,(struct sockaddr*)&sa,sizeof(sa));
佩罗(“绑定”);
听(s,0);
佩罗尔(“倾听”);
而(1){
int conn=接受(s,NULL,NULL);
佩罗(“接受”);
关闭(康涅狄格州);
perror(“关闭”);
}
返回0;
}
这种方法的优点是,流程之间不需要父/子关系。此外,手册页(
setsockopt(7)
)表明,与传统方法相比,这种方法的性能有所提高


在这种情况下,您可以在调用
socket
之前进行分叉。唯一的要求是所有涉及的进程在其套接字上设置
SO\u REUSEPORT
,并共享相同的有效UID

实际上两者都不正确,看最后一个例子。@RomainHippeau谢谢。第二个例子不是我所理解的pre-fork。这太酷了!它可能在Mac OS X中不起作用,所以我对启用pre-fork进行重构的那天不会感到太难过,但我肯定会在Linux中寻找使用它的方法。请务必检查。所以当它登陆时,REUSEPORT是一个更大的东西,我可以想象BSDs和Mac OS也实现了这一点。看到编辑,我发现一个苹果主页建议可以使用REUSEPORT。谢谢,我的pre fork不能很好地与Haskell的epoll事件管理器配合,所以我将不得不求助于这些;-)很高兴知道它在Mac中!
s = socket 
bind s 
listen s 
fork .... 
   conn = accept s