На сервере есть одна проблема:
server_data = conn.recv(1024).decode("utf-8")
conn.recv(1024)
может принимать любое количество байтов от 0 (закрытое соединение) до 1024. В строке выше предполагается, что сообщение целиком принимается каждый раз,но когда это терпит неудачу, это только получает часть сообщения.Ниже я изменил ваш код, чтобы сервер мог обрабатывать несколько клиентских подключений по одному, и клиент будет снова и снова подключаться / отключаться, чтобы ускорить сбой:
Сервер:
import socket
from random import sample
def main():
host = ''
port = 4444
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.bind((host, port))
print('Socket bind accomplished...\n')
print("Listening for an incoming connection...")
kulmiye.listen()
while True:
conn, addr = kulmiye.accept()
print('Connected with ' + addr[0] + ':' + str(addr[1]))
with conn:
server_data = conn.recv(1024).decode("utf-8")
print(f'server_data={server_data}')
game_data = server_data.split(",")
print("From Client: " + str(game_data))
if server_data:
if game_data[0] == "Lotto_Max":
nval = int(game_data[1])
lval = int(game_data[2])
for nval in range(nval):
for i in range(lval):
numbers = sample(range(1, 50), 7)
numbers.sort()
sortedd = str(numbers)
print(sortedd)
print("--------------------")
conn.sendall(sortedd.encode("utf-8"))
liners = "-----------------------"
conn.sendall(liners.encode("utf-8"))
conn.sendall(b'goodbye')
if __name__ == '__main__':
main()
Клиент:
import socket
import argparse
def client():
host = 'localhost'
port = 4444
kulmiye = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
kulmiye.connect((host, port))
kulmiye.sendall(bytes(tvar.encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(nval).encode("utf-8")))
kulmiye.sendall(bytes(','.encode("utf-8")))
kulmiye.sendall(bytes(str(lval).encode("utf-8")))
server_data = kulmiye.recv(1024).decode("utf-8")
while server_data != 'goodbye':
server_data = kulmiye.recv(1024).decode("utf-8")
print('Server: \n' + server_data)
# client_data = input("#\t")
if not server_data:
break
kulmiye.close()
tvar = 'Lotto_Max'
nval = 1
lval = 1
if __name__ == "__main__":
while True:
client()
Вот результат после 100 с успешных соединений.Примечание server_data
между успешным и неудачным соединением:
Connected with 127.0.0.1:12175
server_data=Lotto_Max,1,1
From Client: ['Lotto_Max', '1', '1']
[4, 7, 9, 12, 24, 31, 48]
--------------------
Connected with 127.0.0.1:12176
server_data=Lotto_Max,1,
From Client: ['Lotto_Max', '1', '']
Traceback (most recent call last):
File "C:\server.py", line 38, in <module>
main()
File "C:\server.py", line 24, in main
lval = int(game_data[2])
ValueError: invalid literal for int() with base 10: ''
conn.recv(1024)
не получил полное сообщение (не получил окончательный 1
).TCP - это протокол потоковой передачи байтов без понятия границ сообщения.Ваш код отвечает за вызов recv()
и буферизацию данных до получения полного сообщения.Вы можете отправлять сообщения фиксированного размера и вызывать recv до тех пор, пока у вас не будет такого количества байтов, завершить сообщение байтом сторожа, таким как символ новой строки (\n
), и читать до получения сторожа, или посылать размер сообщения, за которым следуетбайтами сообщения.
Я не буду решать это за вас, так как это назначение, но как подсказка socket.makefile
может обернуть сокет в файлоподобный объект, где вы можете вызвать .read(n)
длячитайте ровно n
байтов из сокета или .readline()
, чтобы прочитать \n
строку с окончанием.
Вот ссылка на мой ответ, который демонстрирует это: https://stackoverflow.com/a/55840026/235698
Другой пример потоковой природы TCP - на стороне клиента.Иногда он печатает:
-----------------------
Server:
goodbye
Server:
-----------------------goodbye
Server:
Server:
-----------------------
Server:
goodbye
Отдельные строки на сервере:
conn.sendall(liners.encode("utf-8"))
conn.sendall(b'goodbye')
Иногда получаются единственными recv
в клиенте:
server_data = kulmiye.recv(1024).decode("utf-8")
Опять же, это связано с потоковой природой TCP и отсутствием границ сообщений.Если вы отправляете каждую строку, оканчивающуюся новой строкой, вы можете вызывать recv()
несколько раз, пока не будет обнаружена новая строка, а затем обработать только эту строку.
Другой ответ, иллюстрирующий эту технику, приведен здесь: https://stackoverflow.com/a/55186805/235698.