如何重现“Connection reset by peer”错误

9
我已经了解了tcp中两个臭名昭著的错误之间的区别:
  • [Errno 54] Connection reset by peer
  • [Errno 32] Broken pipe
这两个错误都是由于tcp连接的一侧原因未知而关闭,而另一侧仍在通信。
  • 当另一侧write数据时,会抛出Broken pipe异常
  • 当另一侧read数据时,会抛出Connection reset by peer异常
我可以使用以下Python代码复现Broken pipe异常。
# tcp_server.py
def handler(client_sock, addr):
    try:
        print('new client from %s:%s' % addr)
    finally:
        client_sock.close()   # close current connection directly

if __name__ == '__main__':

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('', 5500))
    sock.listen(5)

    while 1:
        client_sock, addr = sock.accept()
        handler(client_sock, addr)

关于客户端,

>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sock.connect(('', 5500))
>>> sock.send('a')
1
>>> sock.send('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
socket.error: [Errno 32] Broken pipe

当客户端第一次发送信息时,服务器会向客户端发送一个RST数据包,从此之后,每次发送信息都会报错“Broken pipe”。
我理解以上内容,但是当客户端从服务器读取信息时,它总是返回空字符串,而不是抛出“Connection reset by peer”的错误。
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sock.connect(('', 5500))
>>> sock.recv(1024)
''
>>> sock.recv(1024)
''
>>> sock.recv(1024)
''
>>> sock.recv(1024)

我对此感到困惑,或者说不知道如何重现“Connection reset by peer”的错误?

你可以按照这里所述的方式,使用SO_LINGER选项发送重置信号:https://dev59.com/zmw15IYBdhLWcg3wuuCn#6440364 - tdelaney
@tdelaney 仍然接收到空字符串。 - Jiacai Liu
它对我起作用了。我不得不在服务器上添加一个短暂的等待时间,以便RST不会随着连接返回。 - tdelaney
1个回答

8
您可以将套接字的“linger”选项设置为0并关闭套接字以发送复位。更新您的服务器。
import socket
import struct
import time

# tcp_server.py
def handler(client_sock, addr):
    try:
        print('new client from %s:%s' % addr)
        time.sleep(1)
    finally:
        client_sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
            struct.pack('ii', 1, 0))
        client_sock.close()   # close current connection directly

if __name__ == '__main__':

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('', 5500))
    sock.listen(5)

    while 1:
        client_sock, addr = sock.accept()
        handler(client_sock, addr)

并且运行此客户端

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('', 5500))
print(sock.recv(1024))

我收到了

Traceback (most recent call last):
  File "tcpclient.py", line 5, in <module>
    print(sock.recv(1024))
ConnectionResetError: [Errno 104] Connection reset by peer

谢谢。你的代码确实抛出了异常。接下来还有一个问题:为什么sendrecv的行为不同呢? - Jiacai Liu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接