首页 文章

当tcp服务器在接受之前绑定并分叉时会发生什么?哪个进程会处理客户端请求?

提问于
浏览
1

在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 回答

  • 2

    Linux wait_queue_head实现由有序数据结构(用作队列的链表)组成 . 新的等待任务被添加到队列的末尾,并且从头部完成唤醒(参见 __wake_up_common 中的 __wake_up_common ) . 此外,只有一个任务被唤醒(就像在套接字代码之外的许多地方),因为当只有一个任务可以获得有问题的资源时,必须安排所有任务通常是没有意义的(参见 inet_csk_wait_for_connect 中的注释 net/ipv4/inet_connection_sock.c ) .

  • 3

    我刚刚在Linux 3.4上测试了这种行为,它的行为方式是内核将在所有调用 accept() 的子进程中进行循环处理 .

    您可以从以下示例Python脚本中看到此行为:

    import socket
    import os
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('127.0.0.1', 4242))
    s.listen(10)
    os.fork()
    os.fork()
    os.fork()
    while True:
       conn, addr = s.accept()
       print 'I am %d and I accepted %s' % (os.getpid(), addr)
       conn.close()
    

    这将创建8个进程,所有进程都绑定到端口4242.然后,您可以通过 nc localhost 4242 在本地连接,并观察PID正在接受连接 .

    编辑:如果你从一个更传统的 select 循环中执行此操作,那么所有进程都会被唤醒,并且在调用 accept() 时会出现争用,除了其中一个进程之外的所有进程都被卡在 accept() 中(这很糟糕,因为它阻止了选择循环) .

相关问题