Python recv сокета не дает хорошего результата - PullRequest
1 голос
/ 02 августа 2020

Я пытаюсь составить программу для своего курса ИТ. Суть программы в том, чтобы иметь клиентское приложение для отправки команд на сервер. Похоже, что до сегодняшнего дня он работал довольно хорошо, когда после нескольких звонков, когда я получаю ответ от сервера, он не является актуальным.

например: я отправляю несколько команд, которые все работают нормально. Но затем отправьте другую команду и получите ответ от предыдущей.

Я проверил команду, отправленную клиентом, и это та, которую я набираю, и в серверной части, когда я получаю команду от клиента, она - это тот, который фактически отправляется клиентом (а не предыдущий)

Вот классы 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()

Заранее благодарю за вашу помощь, Сердечно, Sasquatch

1 Ответ

1 голос
/ 03 августа 2020

Поскольку вы сказали, что ответ устарел, я предполагаю, что вы использовали TCP (вы не опубликовали создание сокета). Как и в упомянутом комментарии, есть 2 вещи, которые вы делаете неправильно:

  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)
Поскольку TCP является потоковым сокетом, принимающая сторона может вернуться из recv до того, как будет получено все сообщение. Вам нужно вызвать его в al oop, проверяя возвращаемое значение на каждой итерации, чтобы правильно обрабатывать разъединения. Что-то вроде:
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")
...