我正在阅读《 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,但这些都不起作用...
谢谢!
答案 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
循环可能永远运行,连续获取零字节,但永远找不到换行符。