首页 > 解决方案 > ConnectionResetError:[Errno 54] 对等方重置连接

问题描述

我正在阅读 << Black Hat Python >> 并尝试第一个 bhnet.py 程序。

在一个终端上,我运行脚本

./bhnet.py -l -p 9999 -c

在另一个终端上,运行脚本

./bhnet.py -t localhost -p 9999

然后输入

<ctrl-D>

或者

ls -alt
<ctrl-D>

第一个终端将返回

File "bhnet.py", line 186, in client_handler
cmd_buffer += client_socket.recv(1024).decode('utf-8')
ConnectionResetError: [Errno 54] Connection reset by peer

以下是该程序的代码

def client_handler(client_socket):
    global upload
    global execute
    global command

    # check for upload
    if len(upload_destination):

        # read all the buffer and write to destination
        file_buffer = ""

        # keep reading til none is available
        while True:
            data = client_socket.recv(1024)

            if not data:
                break
            else:
                file_buffer += data

        # take the bytes and write them out
        try:
            file_descriptor = open(upload_destination,'wb')
            file_descriptor.write(file_buffer)
            file_descriptor.close()

            # acknowledge that file being wrote out
            client_socket.send(f"Successfully save file to {upload_destination}.\r \n")
        except:
            client_socket.send(f"Failed to save file to {upload_destination}.\r \n")

    # check for command execution
    if command:

        while True:
            #pop up a window
            client_socket.send(b"<BHP:#> ")

            # keep receiving data until \n
            cmd_buffer = ""
            while "\n" not in cmd_buffer:
                cmd_buffer += client_socket.recv(1024).decode('utf-8')
            response = run_command(cmd_buffer)
            client_socket.send(response)

我用谷歌搜索,甚至尝试升级openssl,但这些都不起作用......

提前致谢!

标签: python-3.xsockets

解决方案


由于您不提供客户端代码,因此很难确定。但是,我相当有信心这种情况正在发生:

当您键入 Ctrl-D 时,您将给客户端的输入一个文件结尾。这导致客户端close连接到它之前连接到服务器的套接字。这样做会导致客户端的操作系统向FIN服务器发送 TCP 数据包。FIN唯一告诉服务器客户端数据发送完毕;在正常的 TCP 会话终止中,无法告诉对等方该对等方可能不再发送任何数据。

但是在客户端关闭其套接字之后,服务器正在尝试访问客户端。send当您尝试在关闭的套接字上发送更多数据时,目标对等方的操作系统会发送一个 TCPRST数据包。这实际上并没有报告给服务器,send因为send当数据被复制到内核时函数调用已经完成——而内核RST可能会在它实际向对等方发送数据包后几毫秒后接收到。

因此,该条件将在套接字上的下一个操作上报告,这里是recv。因此,您的程序会返回一个ECONNRESET错误,python 会将其转换为ConnectionResetError异常。

换句话说:

Client            Server
------            ------
close()
        FIN =>    <OS receives FIN>
                  send(data)
        <= "data"
        RST =>
                  recv
                  <ECONNRESET>

还有一件事:根据确切的时间,您recv在该循环中的第一次调用实际上可能会得到一个文件结束指示符(即零字节)。但是,您并没有对此进行检查,recv只要缓冲区中没有换行符,您就继续调用。你真的应该检查你是否得到了一个零字节字符串,recv并在这种情况下终止你的循环。

一旦在套接字上获得了文件结束指示符,就永远不会在缓冲区中添加换行符。如果客户端在关闭套接字之前实际上已经成功接收到您发送的数据,则不会RST发送任何数据。在这种情况下,您的recv循环可能会永远运行,连续返回零字节但永远找不到换行符。


推荐阅读