ConnectionResetError:[Errno 54]对等重置连接

时间:2018-07-13 14:26:03

标签: python-3.x sockets

我正在阅读《 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)

我用Google搜索,甚至试图升级openssl,但这些都不起作用...

谢谢!

1 个答案:

答案 0 :(得分:2)

由于您不提供客户端代码,因此很难确定。但是,我对此很有信心:

当您输入Ctrl-D时,您将把文件结尾作为客户端的输入。这导致客户端close先前连接到服务器的套接字。这样做会导致客户端的操作系统向服务器发送TCP FIN数据包。 FIN仅告诉服务器客户端已完成发送数据;在正常的TCP会话终止中,没有办法告诉对等端该对等端可能不再发送任何数据。

但是在客户端关闭其套接字之后,服务器 尝试send到客户端。当您尝试在封闭的套接字上发送更多数据时,然后目标对等方的操作系统会发送一个TCP RST数据包。实际上并没有报告给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循环可能永远运行,连续获取零字节,但永远找不到换行符。