在linux中,我编写了一个标准的tcp服务器(使用互联网套接字),但差别很小 . 这是服务器的骨架
fd=socket(...);
bind(...);
listen(...);
//now do a fork
fork();
//this will create two processes bound to the same server listening on the same port !!
clientfd=accept(...);
当客户端连接到侦听端口上的服务器时会发生什么 . 哪个进程会接受连接?
从程序的实际运行中,总是父(分叉的进程)获取客户端请求 . 我想知道这背后的理论 . 父进程收到请求只是偶然的吗?
现在我杀死了父进程 . 所以只有子进程在运行 . 当客户端尝试连接到同一端口号上的服务器时,子进程(或单独的幸存者)进程获得连接 . 这种行为是如何解释的?
2 回答
Linux wait_queue_head实现由有序数据结构(用作队列的链表)组成 . 新的等待任务被添加到队列的末尾,并且从头部完成唤醒(参见
__wake_up_common
中的__wake_up_common
) . 此外,只有一个任务被唤醒(就像在套接字代码之外的许多地方),因为当只有一个任务可以获得有问题的资源时,必须安排所有任务通常是没有意义的(参见inet_csk_wait_for_connect
中的注释net/ipv4/inet_connection_sock.c
) .我刚刚在Linux 3.4上测试了这种行为,它的行为方式是内核将在所有调用
accept()
的子进程中进行循环处理 .您可以从以下示例Python脚本中看到此行为:
这将创建8个进程,所有进程都绑定到端口4242.然后,您可以通过
nc localhost 4242
在本地连接,并观察PID正在接受连接 .编辑:如果你从一个更传统的
select
循环中执行此操作,那么所有进程都会被唤醒,并且在调用accept()
时会出现争用,除了其中一个进程之外的所有进程都被卡在accept()
中(这很糟糕,因为它阻止了选择循环) .