Почему я вижу пустую строку?

Я уже несколько дней пытаюсь разобраться с этим кодом. У меня есть клиент и сервер, которые обмениваются данными в виде двух сообщений: первое - это длина сообщения, а второе - само сообщение. Однако сервер вместо ожидаемой строки возвращает только строку пробелов. 

Вот метод .send на стороне клиента: 
```python
def send(msg: str, client: socket.socket):
    msg_length = len(msg)
    send_length = str(msg_length).encode(FORMAT)
    send_length += b' ' * (HEADER - len(send_length))  # Заполнение пробелами
    log(f"Отправляем длину: {send_length.decode(FORMAT)}")
    client.send(send_length)
    client.send(msg.encode(FORMAT))
    log(f"Отправляем сообщение: {msg}")
```

Теперь метод .receive() на стороне сервера:
```python
def receive(conn: socket.socket):
    # Получение длины сообщения
    msg_length = conn.recv(HEADER).decode(FORMAT).strip()  # Убираем пробелы
    if msg_length.isdigit():
        msg_length = int(msg_length)
        log(f"Полученная длина: {msg_length}")
        msg = conn.recv(msg_length).decode(FORMAT)
        log(f"Полученное сообщение: {msg}")
        return msg
    else:
        return None
```

В консоли я вижу, что сервер успешно получает длину сообщения, равную 11 байтам, и ожидает сообщение этой же длины. Однако вместо правильной строки я получаю только 11 пробелов. Какова может быть причина этой проблемы?
  • 20 октября 2024 г. 13:43
Ответы на вопрос 2
Проблема, с которой вы столкнулись, скорее всего связана с тем, что вы используете заполнение пробелами для длины сообщения, и в то время как сервер правильно обрабатывает длину, он не получает корректное сообщение из-за особенностей работы с сокетами.

Вот несколько рекомендаций и шагов, которые помогут вам исправить это:

1. **Измените подход к заполнению**:
   Вместо заполнения пробелами можно использовать нули или другой фиксированный символ, который не будет ни частью длины сообщения, ни самим сообщением. Например, можно использовать `b'\0'` для заполнения.

2. **Используйте правильный код для обработки фиксированной длины**:
   После получения значения `msg_length` на сервере, перед передачей фактического сообщения убедитесь, что вы правильно получаете именно необходимое количество байт. Ваша реализация выглядит правильно, но иногда ошибочно можно легко вызвать `recv` не с тем числом байтов, которое нужно.

3. **Проверьте формат строки**:
   Убедитесь, что строка, которую вы отправляете, действительно не содержит пробелов изначально. Использование `strip()` на строке длины приведет к удалению пробелов, но если на стороне клиента не было установлено корректного заранее значения, это может вызвать проблемы.

Вот пример исправленного метода `send` с учетом рекомендаций:

```python
def send(msg: str, client: socket.socket):
    msg_length = len(msg)
    send_length = str(msg_length).encode(FORMAT)
    send_length += b'0' * (HEADER - len(send_length))  # Используем '0' вместо пробелов
    log(f"Отправляем длину: {send_length.decode(FORMAT)}")
    client.send(send_length)
    client.send(msg.encode(FORMAT))
    log(f"Отправляем сообщение: {msg}")
```

И очень важно убедиться, что `HEADER` - это количество байт, ожидаемых для заголовка (длины сообщения). Если это будет не 64 (например), то отправка и принятие длины сообщения будет работать некорректно.

Что касается `.receive()`, также можно использовать обработку ошибок для того, чтобы убедиться, что вы правильно получаете данные:

```python
def receive(conn: socket.socket):
    # Получение длины сообщения
    msg_length_data = conn.recv(HEADER).decode(FORMAT)
    msg_length = msg_length_data.strip()  # Убираем пробелы
    if msg_length.isdigit():
        msg_length = int(msg_length)
        log(f"Полученная длина: {msg_length}")
        msg = conn.recv(msg_length).decode(FORMAT)
        log(f"Полученное сообщение: {msg}")
        return msg
    else:
        log(f"Ошибка: полученная длина не является числом: {msg_length_data}")
        return None
```

Если после этих изменений проблема останется, можно добавить дополнительные логи для отслеживания, как данные передаются и принимаются, а также проверить исходные данные перед отправкой.
send_length += b' ' * (HEADER - len(send_length)) 
Я не вполне понял, но зачем ты сразу после длины сообщения дописываешь пробелы?
Да ещё с ориентировкой на длину строкового представления длины сообщения ?
Не говоря уже о том, что ты фиксируешь длину сообщения в символах, а передаёшь сообщение в байтах в некоторой кодировке... а ведь есть многобайтовые кодировки, типа utf-8. Там эти длины не будут совпадать, и более того, две строки одной длины в символах могут иметь разную длину в байтах, и наоборот.
Ну и до кучи, ты передаёшь длину сообщения как строку. А как ты определишь длину этой строки?
Похожие вопросы