为什么socket.accept()会中断未完成的连接?

-1 投票
1 回答
52 浏览
提问于 2025-04-12 23:53

我搜索了很多帖子,但还是找不到答案。我明白 socket.accept() 实际上是从已经连接的队列中获取一个套接字。而且我知道因为阻塞IO的原因,我们需要依靠并发来处理多个连接。

不过,我想问的是 socket.accept() 还有什么其他作用?它会断开已经建立的连接吗? 在我的实验中,我用一个线程来接受新连接,并且不去处理它。换句话说,我故意不使用 recv(),因为我想保持每个请求,以便保持多个连接。

我用几个客户端发送消息。令人惊讶的是,只有一个连接能够维持。以下是我的代码。

在服务器端(在Linux服务器上):

import time
import socket

HOST = "0.0.0.0"  
PORT = 65432 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()

while True:
    conn, addr = s.accept()

在客户端(在Macbook上):

import socket

HOST = "192.168.0.104"
PORT = 65432


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
    print('connect')
    s.send(b"Hello, world")

当我启动服务器时,第一个客户端被阻塞。当我启动第二个客户端时,第一个客户端出现了错误:

Traceback (most recent call last):
  File "/Users/home/xxx/test-client.py", line 14, in <module>
    s.send(b"Hello, world")
BrokenPipeError: [Errno 32] Broken pipe

而第二个客户端则被阻塞。

我的问题是:

  1. 我希望服务器能够保持多个连接,但为什么只有一个能维持?
  2. 如果 socket.accept() 总是会断开已建立的连接,那为什么并发可以正常工作?

正如 @Mark Tolonen 所说,原因是垃圾回收。当我使用以下代码片段时,我可以看到多个连接得以维持。

#!/usr/bin/env python3
import time
import socket

HOST = "0.0.0.0"  
PORT = 65432 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen()

connections = []
while True:
    conn, addr = s.accept()
    connections.append(conn)

我想感谢大家的帮助,但我想在这里留个言,抱怨一下当前StackOverflow的文化。

在我问这个问题之前,我花了几天时间深入研究套接字,并调查了相关问题。对一些观众来说,这可能看起来很简单,但我真的不明白为什么有人会觉得这是个糟糕的问题。一个人的问题对其他人来说可能总是太简单,但对提问者来说却很难,他只能通过学习来成长。这也给其他可能遇到相同挑战的人提供了机会。让我们保持StackOverflow的开放性。

1 个回答

3

通过 accept() 方法得到的 conn 对象是有引用计数的。当第二个连接被赋值给 conn 时,第一个连接就没有被引用了,这样它就会被垃圾回收机制处理掉,也就是关闭了这个连接。所以你需要把每个连接都保存起来。

撰写回答