python-3.x - 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,但这些都不起作用......
提前致谢!
解决方案
由于您不提供客户端代码,因此很难确定。但是,我相当有信心这种情况正在发生:
当您键入 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
循环可能会永远运行,连续返回零字节但永远找不到换行符。
推荐阅读
- sql - SSIS 中的自动字符串模式匹配
- javascript - 用于赋值的 JS/jQuery
- angular - 如何在 Angular 4+ 中获得 FormControl 的完整路径
- php - phantomJs 权限被拒绝
- javascript - 使用 iframe 在 Nativescript Webview 中上传文件
- c++ - OpenCV C++:显示强度降低的 DFT 带通滤波图像
- wpf - 数据上下文对象的 WPF DataContext 问题
- asp.net-mvc - 如何使用 ActionResult 返回 null
- c# - LINQ Group By Join
- javascript - W3 幻灯片实现无法正常工作