You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket的shutdown()与close()差异:替换后curl报错原因解析

Socket中close()引发curl连接重置的原因

场景复现

正常运行的服务端代码

if __name__ == "__main__":
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    soc.bind(("127.0.0.1", 4000))

    while True:
        soc.listen(5)
        conn, address = soc.accept()

        data = conn.recv(32)
        print(f"got data: {data}")
        conn.sendall(response.encode())
        conn.shutdown(socket.SHUT_WR)

修改后触发错误的代码

将代码中的conn.shutdown(socket.SHUT_WR)替换为conn.close():

if __name__ == "__main__":
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    soc.bind(("127.0.0.1", 4000))

    while True:
        soc.listen(5)
        conn, address = soc.accept()

        data = conn.recv(32)
        print(f"got data: {data}")
        conn.sendall(response.encode())
        conn.close()

测试命令及错误响应

执行curl命令:

curl http://localhost:4000

收到错误响应:

curl: (56) Recv failure: Connection was reset
中文翻译:curl: (56) 接收失败:连接已重置

另外存在两个特殊现象:

  • 使用shutdown(socket.SHUT_WR)时运行完全正常
  • 在close()后添加time.sleep()或打印操作,也能正常运行

原因分析

核心差异在于shutdown和close对TCP连接的处理逻辑:

  1. shutdown(SHUT_WR)的行为:
    这是TCP半关闭操作,仅关闭连接的写方向,告知客户端“服务端已无数据发送”,但读方向仍保持开放。此时服务端会向curl发送FIN包,curl收到后可正常完成响应读取流程,按TCP四次握手关闭连接,不会触发重置。

  2. close()的行为:
    close()会直接关闭套接字的读写双向。问题出在调用时机:当sendall()执行完毕后,响应数据可能仍在TCP发送缓冲区中,未完全发送到网络。此时立刻调用close(),操作系统可能直接发送RST包终止连接,而非等待缓冲区数据发送完成并完成四次握手。curl在等待完整HTTP响应时收到RST包,就会抛出“连接已重置”错误。

  3. 添加sleep/打印后正常的原因:
    这类操作给了TCP缓冲区足够时间,将响应数据完全发送到网络,完成与curl的交互后再关闭套接字,自然不会触发RST。

注:每次curl都是新连接,但问题出在单个连接的关闭流程上,与新连接本身无关。

内容的提问来源于stack exchange,提问作者mohamed naser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 07:57:14