У вас здесь несколько проблем.Первый и основной из них заключается в том, что основной цикл вашего сервера испорчен.Каждый раз в цикле ваш сервер хочет accept
соединение.Таким образом, первый клиент для подключения будет принят, и сразу же будет получено его первое сообщение.Но другой клиент еще не был принят и поэтому не получит это первое сообщение.Затем второе клиентское соединение принимается и его первое сообщение затем отправляется обоим клиентам, но затем цикл повторяется снова, и с сервера больше не будут отправляться сообщения до третьего клиента соединяет.И т. Д.
Таким образом, вам необходимо разделить принимающие соединения и прием сообщений.Это можно сделать несколькими способами.Самый простой способ - использовать функцию select
для одновременного ожидания нескольких сокетов.То есть, если у вас есть список сокетов, включая сокеты прослушивания и ранее принятые, вы должны сделать что-то вроде этого:
# List starts with only listening socket
list_of_sockets = [lsock]
...
while True:
# Wait until some socket becomes "readable"
rfds, _wfds, _xfds = select.select(list_of_socks, [], [])
for sock in rfds:
if sock is lsock:
# Listening socket ready. Accept new connection
c, addr = lsock.accept()
print(f"Accepted {c}")
list_of_socks.append(c)
else:
msg = sock.recv(1024)
if msg:
# Received data from connected socket. Send to all
print(f"Got {msg.decode()} from {sock}")
broadcast(msg)
else:
# Got end of file (this client closed). Remove client from list
print(f"Closed {sock}")
list_of_socks.remove(sock)
Другая проблема с вашим кодом, которая будет не быть адресованным приведенным выше кодом сервера: вы не можете предполагать, что каждое отправленное вами сообщение будет получено как отдельный блокТо есть, если сервер отправляет «Halo», а затем отправляет «Hello» до того, как вы (клиент) выполнили recv
, то, по всей вероятности, all данные будут возвращены за один размах;это «HaloHello».
Как правило, поэтому вы захотите поместить какой-либо разделитель в данные (например, новую строку [\n
] - но тогда вам нужно будет проанализировать полученные данные) или, что еще лучше, поместитьполе фиксированной длины перед каждым сообщением, задающее длину последующей части переменной длины, чтобы вы могли получать и обрабатывать ровно одно сообщение за раз.(В python это обычно включает использование функций struct
модуля pack
и unpack
.) В результате ваш текущий клиентский код, вероятно, не будет должным образом упорядочивать сообщения, как вы хотите.
Также -хотя это менее вероятно, вызовет проблему - то же самое касается send
: вы не должны предполагать, что send(N)
отправляет ровно N
байтов.Может отправлять 1, 2, 3 или N-1
байтов.Вы можете использовать sendall
, чтобы обеспечить отправку всех байтов.