Сокет Python — отсутствует последний символ

#python #python-3.x #sockets

Вопрос:

Итак, я создал клиентский и серверный сокет sing.
И все работает хорошо, но я просто сломался, используя строку из базы данных MySQL.

Сервер:

 import socket import threading   PORT = 9696 SERVER = "localhost" ADDR = (SERVER, PORT) FORMAT = 'utf-8'  server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(ADDR)   def handle_client(conn):  while True:  actual_size = int(conn.recv(30).decode(FORMAT).replace("#", ""))  size = int(actual_size / 1024)  rest_msg = actual_size - (size * 1024)  received_message = ""  for chunk in range(size):  received_message  = conn.recv(1024).decode(FORMAT)  received_message  = conn.recv(rest_msg).decode(FORMAT)  print(rest_msg)  print(len(received_message))   def start():  server.listen()  while True:  conn, addr = server.accept()  thread = threading.Thread(target=handle_client, args=(conn,))  thread.start()   start()  

Клиент:

 import socket import time  HEADER = 64 PORT = 9696 FORMAT = 'utf-8' SERVER = "localhost" ADDR = (SERVER, PORT)  client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(ADDR)   def send(msg):  client.send(msg.encode("utf-8"))   msg_to_send = "Some random message"  time.sleep(3) for i in range(1000):  send(str(len(msg_to_send))   ("#" * (30 - len(str(len(msg_to_send))))   msg_to_send))  while True:  pass  

Если я msg_to_send заменю следующим текстом:

 [('index', 'bigint(20)', 'YES', 'MUL', None, ''), ('LP', 'text', 'YES', '', None, ''), (' NR-a', 'text', 'YES', '', None, ''), ('LITERA-a', 'text', 'YES', '', None, ''), ('MUFA-a', 'double', 'YES', '', None, ''), ('UWAGI-a', 'text', 'YES', '', None, ''), ('TUBY-a', 'double', 'YES', '', None, ''), ('DATA1-a', 'text', 'YES', '', None, ''), ('DATA2-a', 'text', 'YES', '', None, ''), ('SPAWY-i', 'text', 'YES', '', None, ''), ('SPAWY_DAC-i', 'text', 'YES', '', None, ''), ('LOG-a', 'text', 'YES', '', None, ''), ('SPLIT1X4-i', 'text', 'YES', '', None, ''), ('SPLIT1X8-i', 'text', 'YES', '', None, ''), ('SPLIT1X16-i', 'text', 'YES', '', None, ''), ('ADAPTERY SIMPLE-i', 'double', 'YES', '', None, ''), ('ADAPTERY DUPLEX-i', 'double', 'YES', '', None, ''), ('PIGTAIL-i', 'double', 'YES', '', None, ''), ('OLT-a', 'double', 'YES', '', None, ''), ('NEXT-a', 'double', 'YES', '', None, ''), ('ODNOGA_1-a', 'double', 'YES', '', None, ''), ('ODNOGA_2-a', 'double', 'YES', '', None, ''), ('ODNOGA_3-a', 'double', 'YES', '', None, ''), ('ODNOGA_4-a', 'double', 'YES', '', None, ''), ('DROP30-i', 'double', 'YES', '', None, ''), ('DROP50-i', 'double', 'YES', '', None, ''), ('DROP70-i', 'double', 'YES', '', None, ''), ('DROP80-i', 'double', 'YES', '', None, ''), ('DROP100-i', 'double', 'YES', '', None, ''), ('DROP120-i', 'double', 'YES', '', None, ''), ('DROP150-i', 'double', 'YES', '', None, ''), ('DROP200-i', 'double', 'YES', '', None, ''), ('MAŁPKI-i', 'double', 'YES', '', None, '')]  

И это потеряно ] , поэтому следующее сообщение, если оно будет преобразовано в int, чтобы оно могло прочитать, как долго будет следующее сообщение, оно просто выдаст ошибку, например ]6 , str. Я понятия не имею, почему это происходит. Я попробовал использовать другую таблицу из базы данных и изменил размер буфера, но она все еще где-то ест этот мир. И на сервере есть два отпечатка. Сначала покажите буфер, который использовался при получении этого. И второй для отображения того, сколько символов он на самом деле получил, и он всегда работает, но не с этой строкой.

Если я не осветил здесь что-то или какую-то важную информацию, пожалуйста, напишите в комментарии, и я предоставлю ее.

Комментарии:

1. conn.recv() может вернуть меньше, чем вы просите, если вы не используете MSG_WAITALL флаг.

2. Хотя @Barмар прав, это не причина вашей проблемы. Проблема в том, что ваша рабочая строка содержит символ, отличный от ASCII. Таким образом, хотя строка в Юникоде состоит из 1481 символа, и это то, что вы вставляете, когда она преобразуется в UTF-8 для передачи, результирующая строка имеет длину 1482 байта. Вам нужно преобразовать в UTF-8, прежде чем вычислять длину.

3. @TimRoberts Спасибо за исправление. Вы должны опубликовать это в качестве ответа.

Ответ №1:

Ваша проблема в том, что ваша рабочая строка содержит символ, отличный от ASCII, и он преобразуется в несколько байтов при кодировании в UTF-8. Эти несколько байтов не учитываются при передаче длины. Вам нужно захватить длину ПОСЛЕ преобразования. Итак, избавьтесь от функции «отправить» и сделайте:

 msg_to_send = msg_to_send.encode('utf-8') for i in range(1000):  print(len(msg_to_send))  prefix = (str(len(msg_to_send))   "#"*30)[:30].encode('utf-8')  client.send(prefix   msg_to_send)  while True:  time.sleep(5)  

Комментарии:

1. Это работает! Спасибо вам, но что же [:30] делает?

2. Там написано «возьмите первые 30 символов». Вместо того, чтобы утруждать себя вычислением того, сколько # нужно добавить, я просто добавляю 30 и обрываю полученную строку на 30.