Как я могу учесть сообщения разбиты при использовании сокетов?

Мой дизайн

Я использую сокеты для реализации сервера чата.

Клиентская сторона использует Java java.net.Socket а также BufferedReader читать сообщения с сервера.

Серверная часть использует Php socket_read () получать сообщения от клиентов.

И это использует Php’s socket_write () отправлять сообщения с сервера. socket_write () не гарантирует, что все исходное сообщение будет записано, а это значит, что мне, возможно, придется сделать несколько звонков, чтобы отправить исходное сообщение целиком.

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

Обеспокоенность

Я обеспокоен тем, что сообщение может быть разбито на несколько небольших сообщений. Поэтому, когда сервер или клиент читает входящее сообщение, оно может фактически быть фрагментом оригинала.

Вопросы

Это то, что мне нужно учитывать?
Если да, то как?

Возможное решение

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

0

Решение

Да, это то, что вам нужно обработать в вашем протоколе.

Два наиболее типичных подхода здесь:

  1. Сделайте ваш протокол линейно-ориентированным. Завершите каждое сообщение новой строкой и не рассматривайте строку как завершенную, пока не увидите этот символ новой строки. Это, конечно, зависит от новых строк, которые не появляются в сообщениях.

    Некоторые протоколы, которые используют этот подход, включают SMTP, IMAP и IRC.

  2. Включите длину сообщения в его заголовок, чтобы вы знали, сколько данных нужно прочитать.

    Некоторые протоколы, которые используют этот подход, включают HTTP (в Content-Length заголовок) и TLS, а также многие протоколы низкого уровня, такие как IP.

Если вы не уверены, какой подход выбрать, второй значительно легче реализовать и не накладывает никаких ограничений на то, с какими данными вы его используете. Простая реализация может просто хранить количество байтов в виде упакованного целого числа и может выглядеть как следующий псевдокод:

send_data(dat):
send(length of dat as packed integer)
send(dat)

recv_data():
size = recv(size of packed integer)
return recv(buffer)

(Этот код предполагает, что абстрактный send() а также recv() методы будут блокироваться, пока все сообщение не будет отправлено или получено. Ваш код, конечно, должен заставить это работать должным образом.)

1

Другие решения

Если вам нужны сообщения на уровне приложения, то вы должны реализовать их на уровне приложения. Есть несколько общих подходов:

1) Используйте сообщения фиксированной длины.

2) Префикс каждого сообщения с его длиной.

3) Используйте маркер «конец сообщения», который, естественно, никогда не появляется в ваших сообщениях.

4) Используйте маркер конца сообщения и избегайте его, если он появляется в ваших сообщениях.

2