第一次发送到断开连接的套接字成功

Sending to a disconnected socket succeeds the first time

在 TCP 客户端-服务器通信中,当客户端在服务器断开连接后尝试向服务器发送消息时,第一次尝试 send()(据称)成功,所有后续尝试都失败并显示 [Errno 32] Broken pipe.最小示例:

import socket
import sys
import time

SERVER_ADDR = ("127.0.0.1", 65432)


def server(s):
    s.bind(SERVER_ADDR)
    s.listen()
    print(f"Server listening for clients at {SERVER_ADDR}")
    conn, addr = s.accept()
    with conn:
        print("Connected by", addr)


def client(s, msg):
    s.connect(SERVER_ADDR)
    time.sleep(1)
    for i in range(1, 10):
        print(f"Sending {msg} - attempt {i}")
        try:
            nbytes = s.send(msg)
            print(f"{nbytes} bytes sent out of {len(msg)} in total")
        except OSError as ex:
            print(ex)


if __name__ == "__main__":
    msg = " ".join(sys.argv[1:]).encode("utf8")
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        if msg:
            client(s, msg)
        else:
            server(s)
  1. 启动服务器:
python run.py 
Server listening for clients at ('127.0.0.1', 65432)
  1. 启动客户端:
python run.py hello world
Sending b'hello world' - attempt 1
11 bytes sent out of 11 in total
Sending b'hello world' - attempt 2
[Errno 32] Broken pipe
Sending b'hello world' - attempt 3
[Errno 32] Broken pipe
Sending b'hello world' - attempt 4
[Errno 32] Broken pipe
Sending b'hello world' - attempt 5
[Errno 32] Broken pipe
Sending b'hello world' - attempt 6
[Errno 32] Broken pipe
Sending b'hello world' - attempt 7
[Errno 32] Broken pipe
Sending b'hello world' - attempt 8
[Errno 32] Broken pipe
Sending b'hello world' - attempt 9
[Errno 32] Broken pipe

Why does this happen?

this answer to Writing to a closed, local TCP socket not failing里面有详细的解释。

How can I either (a) make the first attempt fail too, or (b) detect if the connection is alive before sending?

您可以通过强制服务器立即关闭套接字来使第一次尝试失败,使用 SO_LINGER 套接字选项,在 s.accept 行之后:

conn.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))