Как отправить последовательность сообщений через сокет? - PullRequest
0 голосов
/ 02 февраля 2019

Я экспериментирую со связью через сокеты в Python.У меня есть файл server.py и client.py.Последний запрашивает ввод пользователя и отправляет его на сервер.В зависимости от ввода пользователя, сервер воспроизводит 2 разных звука.Это работает один раз, но не для второй попытки.

Я вставил несколько строк печати (XYZ), чтобы увидеть, где останавливается программа.После отправки первого сообщения строка print ("...") "моего server.py больше не выполняется.Таким образом, похоже, что server_socket.accept () больше не успешен.Почему это так?

Это server.py:

import socket
import winsound

fnameBeep = "beep.wav"
fnameBop = "bop.wav"

server_socket = socket.socket(socket.AF_INET,
                              socket.SOCK_STREAM)
server_addr = ("127.0.0.1", 1337)
server_socket.bind(server_addr)
server_socket.listen(1000)
while True:
    print("waiting...")
    (client_socket, addr) = server_socket.accept()
    print("...")
    msg = client_socket.recv(1024)
    print(msg)
    print("Received: " + str(msg, "utf8"))
    if str(msg, "utf8") == '1':
        winsound.PlaySound(fnameBeep, winsound.SND_FILENAME)
    else:
        winsound.PlaySound(fnameBop, winsound.SND_FILENAME)    

Это client.py:

import socket

client_socket = socket.socket(socket.AF_INET,
                              socket.SOCK_STREAM)
server_addr = ("127.0.0.1", 1337)
print("Beep = 1; Bop = 2")
client_socket.connect(server_addr)
while True:
    print('waiting ...')
    UserInput = input('Your choice: ')
    print('Sending: ' + UserInput)
    client_socket.send(bytes(UserInput, "utf8"))
    print('Sent!')

Что не так?общее сообщение работает, но я хотел бы отправить последовательность сообщений на сервер.

1 Ответ

0 голосов
/ 02 февраля 2019

Первое, что вам нужно сделать, это переместить ваш вызов accept() выше верхней части вашего цикла while - так как ваш код пытается принять новое TCP-соединение после каждой команды,что я думаю, что это не то, что вы хотели сделать - по-видимому, вы хотите оставить одно TCP-соединение открытым и вместо этого получать несколько команд по этому TCP-соединению.

Вторая проблема - создание: вещь, которую нужно помнить о TCPзаключается в том, что он реализует необработанный поток байтов и не выполняет никаких фиксированных кадров сообщений - например, если вы выполняете следующие вызовы на стороне отправителя:

client_socket.send("123")
client_socket.send("456")
client_socket.send("789")

...на принимающей стороне сервер может увидеть следующие фрагменты данных, возвращенные его последующими вызовами recv ():

recv() call #1:  12345
recv() call #2:  67
recv() call #3:  89

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

recv() call #1:  1
recv() call #2:  2345678
recv() call #3:  9

, или он может получить все отправленные данные за один вызов:

recv() call #1:  123456789

, или он может даже получить каждый байт черезотдельныйпозвоните:

recv() call #1:  1
recv() call #2:  2
recv() call #3:  3
recv() call #4:  4
recv() call #5:  5
recv() call #6:  6
recv() call #7:  7
recv() call #8:  8
recv() call #9:  9

... или любой другой комбинации, которую вы можете себе представить.

Таким образом, вопрос, учитывая неопределенность группировки данных, как ваш получатель может знать, что ваш клиентпредназначен для отправки ("file_name1.wav", а затем "file_name2.wav"), а не просто ("file_name1.wavfile_name.wav") или ("file", " name1.wavfile ", "name.wav ") или т. д.?

Чтобы однозначно проанализировать входящие байты TCP, получатель должен знать, как они вставлены .Для такой простой программы, как ваша, логика кадрирования может быть простой - например, просто объявить правило, что каждая строка будет иметь символ новой строки в конце.Затем ваш сервер может просто продолжать получать байты (и добавлять их в конец строки) до тех пор, пока не увидит байт новой строки, и в этот момент он узнает, что получил полную пользовательскую команду, поэтому в этот момент он может обработать эту команду,затем удалите всю строку (до и включая символ новой строки) перед продолжением ее анализа для следующей строки.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...