关于Socket.listen方法的一点体悟

  欢迎参与讨论,转载请注明出处。

前言

  最近在接触Socket的的时候,关于其中的listen方法感到不解,于是对其进行了一番研究,得出了一点体悟,特此记录。

详解

  让我们先来看看listen方法在Python3.6文档说明:

1
2
3
4
5
6
7
socket.listen([backlog])
Enable a server to accept connections. If backlog is specified, it must be at least 0 (if it is lower, it is set to 0); it specifies the number of unaccepted connections that the system will allow before refusing new connections. If not specified, a default reasonable value is chosen.
启用服务器以接受连接。如果指定backlog,则必须至少为0(如果低于0,则设置为0);它指定系统在拒绝新连接之前将允许的未接受连接的数量。如果未指定,则选择默认的合理值。
Changed in version 3.5: The backlog parameter is now optional.
在版本3.5中已更改: backlog参数现在是可选的。

  起初我看了这说明想当然的以为是可以接入的Client上限,不过实践过后发现并非如此。在网上找的解答基本上就是文档所言的复述,后来请教了专业人士后,方知这涉及到Socket的底层知识。
  在了解listen方法之前,首先我们需要了解connect方法和accept方法,以下是文档说明:

1
2
3
4
5
6
7
8
9
10
socket.connect(address)
Connect to a remote socket at address. (The format of address depends on the address family — see above.)
在地址连接到远程套接字。(地址的格式取决于地址系列 - 请参见上文)
If the connection is interrupted by a signal, the method waits until the connection completes, or raise a socket.timeout on timeout, if the signal handler doesn’t raise an exception and the socket is blocking or has a timeout. For non-blocking sockets, the method raises an InterruptedError exception if the connection is interrupted by a signal (or the exception raised by the signal handler).
如果连接被信号中断,则该方法等待直到连接完成,或者如果信号处理程序没有引发异常并且套接字正在阻塞或者已经阻塞,则在超时时引入socket.timeout超时。对于非阻塞套接字,如果连接被信号中断(或由信号处理程序引发的异常),则该方法引发InterruptedError异常。
Changed in version 3.5: The method now waits until the connection completes instead of raising an InterruptedError exception if the connection is interrupted by a signal, the signal handler doesn’t raise an exception and the socket is blocking or has a timeout (see the PEP 475 for the rationale).
在版本3.5中已更改:该方法现在等待直到连接完成,而不是提高InterruptedError异常,如果连接被信号中断,信号处理程序不引发异常,套接字阻塞或超时(参见 PEP 475)。
1
2
3
4
5
6
7
8
9
10
11
12
13
socket.accept()
Accept a connection. The socket must be bound to an address and listening for connections. The return value is a pair (conn, address) where conn is a new socket object usable to send and receive data on the connection, and address is the address bound to the socket on the other end of the connection.
接收一个连接.该socket 必须要绑定一个地址和监听连接.返回值是一对(conn, 地址)其中conn是新 t4 > socket对象可用于在连接上发送和接收数据,address是连接另一端的套接字的地址。
The newly created socket is non-inheritable.
新创建的套接字non-inheritable。
Changed in version 3.4: The socket is now non-inheritable.
在版本3.4中更改:套接字现在是不可继承的。
Changed in version 3.5: If the system call is interrupted and the signal handler does not raise an exception, the method now retries the system call instead of raising an InterruptedError exception (see PEP 475 for the rationale).
在版本3.5中更改:如果系统调用中断并且信号处理程序没有引发异常,则此方法现在重试系统调用,而不是引发InterruptedError异常 PEP 475)。

  相比listen方法,它俩就好理解多了,一个是Client用于连接Server的方法,一个是Server用于接收Client的连接申请的方法。
  但事实上accept方法一次只能接收一个Client的连接申请,而Client则是多个的,这样Socket会设计一个队列来存储Client的连接申请则是理所当然的。于是accept便从这个队列里提取首位成员处理即可。以下是示意图:1

  如此便很清晰了,backlog参数的含义便是这个队列的最大值,也就是同时受理连接申请的最大值。关于backlog该设置为多少,从Skynet得到的参考为32。如果满了便需要Client重新connect。以上listen方法之谜便解开了。

后记

  不得不说网络编程的水真的很深,我也得买点书充充电了,目前的目标为啃下谢希仁著的《计算机网络》。另外推荐《TCP/IP详解》及《UNIX网络编程》。