Почему эта система клиент-сервер не работает (просто) - PullRequest
0 голосов
/ 26 октября 2019

Я пытаюсь сделать очень простую клиентскую систему простой, и я не уверен, что с ней не так. Предполагается, что это калькуляторная система. Вот код для клиента:

import socket

IP = '127.0.0.1'
PORT = 8106

my_socket = socket.socket()
my_socket.connect((IP, PORT))


done = False

while not done:
    command = raw_input("choose a command from [ADD, SUB, MUL, DIV, EXIT]")
    command = command.upper()
    my_socket.send(command)
    data = my_socket.recv(20)
    new_list = data.split(":")
    if command in ["ADD", "SUB", "MUL", "DIV", "EXIT"]:
        if command == "ADD":
            print new_list[0] + "+" + new_list[1] + "=" + new_list[2]
        if command == "SUB":
            print new_list[0] + "-" + new_list[1] + "=" + new_list[2]
        if command == "MUL":
            print new_list[0] + "*" + new_list[1] + "=" + new_list[2]
        if command == "DIV":
            print new_list[0] + "/" + new_list[1] + "=" + new_list[2]
        if command == "EXIT":
            done = True
    else:
        print 'not valid'






, а вот код сервера:

import socket
import random

IP = '0.0.0.0'
PORT = 8106

server_socket = socket.socket()
server_socket.bind((IP, PORT))

server_socket.listen(1)

(client_socket, client_address) = server_socket.accept()


done = False

while not done:
    message = client_socket.recv(4)
    num1 = random.randint(-101, 100)
    print num1
    num2 = random.randint(-101, 100)
    print num2
    if message in ["ADD", "SUB", "MUL", "DIV", "EXIT"]:
        if message == "ADD":
            result = num1 + num2
        elif message == "SUB":
            result = num1 - num2
        elif message == "MUL":
            result = num1 * num2
        elif message == "DIV":
            result = float(num1) / float(num2)
        elif message == "EXIT":
            done = True
        client_socket.send(str(num1) + ":" + str(num2) + ":" + str(result))
    else:
        client_socket.send("0:0:0")

Теперь, когда я запускаю сервер, а затем клиента и выбираю "DIV "пару раз, первый раз также работает, но при второй или третьей попытке я получаю сообщение об ошибке:

print new_list[0] + "/" + new_list[1] + "=" + new_list[2]
IndexError: list index out of range

Я не уверен, почему это происходит. Я пытался напечатать «данные», чтобы попытаться решить ее, и иногда данные - это просто одно число, например, просто 46, а не что-то вроде 46: 3: 15.333

Почему это происходит?

Ответы [ 2 ]

0 голосов
/ 27 октября 2019

socket.send не гарантирует посылку полных данных. Ваше приложение должно проверить, сколько байтов было отправлено, исходя из socket.send возвращаемого значения.

В качестве альтернативы просто используйте socket.sendall и проверьте наличие таких исключений:

try:
    s.sendall(MESSAGE)
except socket.error:
    # failed to send

См. socket.send иsocket.sendall в документах .

0 голосов
/ 27 октября 2019

Документы для метода socket.recv (bufsize [, flags]) указывают следующее:

Максимальный объем данных, принимаемых за один раз, определяетсяbufsize.

Ключевая часть заключается в том, что bufsize - это максимальное количество байтов, которое вы можете получить за один вызов, поэтому отдельные строки байтов, которые вы получаете, могут быть не совсем точнымите же по количеству и размеру, что и те, которые вы называли send с другой стороны.

Единственное, что равно , гарантировано для сокета, созданного с типом по умолчанию (SOCK_STREAM т. Е. TCP) означает, что ваш поток байтов будет поступать в том же порядке, в котором они были отправлены.

Поэтому вам придется разработать протокол, который позволит как клиенту, так и серверу идентифицировать границы каждого отдельного пользователя. message.

Вот несколько способов добиться этого:

  1. Включите информацию о длине каждого сообщения в самом сообщении. Например, первый байт каждого сообщения может быть целым числом, которое задает длину остальной части сообщения, давая максимальный размер сообщения 255 (исключая префикс длины).
  2. Сделайте каждое сообщение одинаковым размером,Таким образом, вам не нужно кодировать длину сообщения - вы можете просто продолжать вызывать recv, пока не получите ожидаемое количество байтов. Вы должны убедиться, что вы можете выразить каждое число в том же формате и длине, хотя.

Редактировать: согласно ответу Кирилла , вам также придется исправить свой коддля отправки данных (например, используя sendall). Невозможно сказать, какая из этих проблем вызывает вашу проблему без дополнительной информации.

...