多进程 accept

pid_t pid;
int listenfd, connfd;
listenfd = Socket(...);

Bind(listenfd, ...);
Listen(listenfd, LISTENQ);
for(;;) {
    connfd = Accept(listenfd, ...);
    if( (pid = Fork()) == 0) {
        Close(listenfd);
        doit(connfd);
        Close(connfd);
        exit(0);
    }
    Close(connfd);
}
  • 以上为经典并发服务器轮廓(节选至UNIX 网络变成卷1)

    • 对于子线程来说不需要关注父进程的 listenfd,所以 fork 后应该先 close listenfd
    • 新连接由子进程提供服务,所以父进程再 fork 后可以 close connfd
  • 调用 close 是否会关闭 socket

    • 实际上调用 close 只是导致相应的描述符引用计数减一,套接字真正的清理和资源释放发生需要其引用计数到达 0 时才发生
  • 父进程为什么需要 close connfd

    • 若不关闭,fork 结束后,connfd 的引用计数为2,子进程结束后,connfd 引用计数由 2递减为 1,(a)这将导致 fd 一直存在,耗尽父进程的可用文件描述符而且(b)连接会一直存在占用资源