在子进程之后关闭套接字。只要子进程仍在运行,它就会在TIME_WAIT中保留套接字

时间:2013-07-12 02:48:49

标签: python sockets networking tcp subprocess

在Windows 7上:

鉴于此服务器代码:

# in server.py
if __name__ == '__main__':
    serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # uncommenting this won't help
    #serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    serversock.bind(('',8888))
    serversock.listen(5)

    # accept and receive dummy data from client
    clientsock,address = serversock.accept()
    data = clientsock.recv(1024)

    # as long as calc.exe is running, I can't do this again
    subprocess.Popen(r"c:\windows\system32\calc.exe")

    # letting client close first still won't help
    time.sleep(3)

    # closing won't help either
    clientsock.close()
    serversock.close()

客户端代码

# in client.py
if __name__ == '__main__':
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('127.0.0.1', 8888))
    s.sendall('Hello, world')
    # close early to help prevent TIME_WAIT on server, but doesn't help
    s.close()

首先运行服务器然后客户端将启动计算器应用程序。

当计算器应用仍在运行时,我无法再次运行服务器。它会抱怨

python server.py (ok)
python client.py (ok)
python server.py (boom!)
socket.error: [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

如果我关闭计算器应用,再次运行服务器就可以了...... 这不会发生在Mac上。

启用SO_REUSEADDR只会使错误消失,但服务器无法从客户端访问。

在上面的示例中,我特意让客户端先关闭,以便服务器套接字不会进入TIME_WAIT。

所以问题:

  1. 我是否遇到了服务器上的TIME_WAIT问题?
  2. 服务器中是否有未关闭的套接字/文件描述符?
  3. 为什么SO_REUSEADDR在这种情况下无效?客户可以来自同一个港口吗?
  4. 孩子的过程可能会挂在某些描述符上吗?
  5. 我该怎么办?
  6. 解决方案:

    问题在于Calculator的父进程持有某个文件描述符。 因此,将close_fds = True添加到Popen将确保所有内容都正确释放。

    subprocess.Popen(r"c:\windows\system32\calc.exe", close_fds=True)
    

1 个答案:

答案 0 :(得分:0)

  

子进程后关闭套接字。只要子进程仍在运行,Popen就会在TIME_WAIT中保留套接字

不,不。它将它留在TIME_WAIT中一段固定的时间,2或4分钟。收盘后它完全与子进程无关。