2015-12-28 18 views
2

如果我这样做(以下伪代码)会发生什么:插座的正确顺序要求预分叉服务器

s = socket 
bind s 
fork .... 
    (... at child ...) 
    listen s 
    conn = accept s 

?我应该改用:

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

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

+0

其实这两个都不正确http://www.tutorialspoint.com/unix_sockets/socket_server_example.htm看最后一个例子。 –

+0

@RomainHippeau谢谢。第二个例子不是前叉,因为我理解它。 – dsign

回答

2

哪一项是正确[,呼吁listen()之前或之后fork()]?

调用listen()fork()是正确的。 listen()的作用是将底层套接字标记为准备好与连接待办事项进行连接。它只需要调用一次。

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

虽然反复调用listen()并没有害处,但它很可疑。该规范没有说明在进行后续调用时会发生什么情况,只是面向连接的套接字应该是"maintain a queue of outstanding connection indications",也就是未决连接的积压。随后的调用是否能够改变积压的大小?你想要它?事实上,并非所有的操作系​​统甚至可以让你查询积压的大小(FreeBSD有,例如,SO_LISTENQLIMIT)。

1

在Linux(因为3.9)(和Mac OSFreeBSD可能还有其他人),你也可以选择使用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。

+0

这是超酷!它可能无法在Mac OS X中运行,所以我不会为重新启用pre-fork而感到不快,但我一定会在Linux中寻找使用这种方法的方法。 – dsign

+0

请务必检查。 SO_REUSEPORT在登陆时是一件更大的事情,我可以想象BSD和Mac OS也实现了这一点。 –

+0

看到编辑,我发现一个苹果手册页,提示SO_REUSEPORT可用。 –