Протокол TCP (Transmission Control Protocol) является потоком байтов и не имеет Konzepta сообщений. Поэтому, есть только три способа для получателя узнать, когда полное сообщение было получено:
Все сообщения фиксированной длины. Получатель просто читает столько байтов каждый раз.
Отправитель отправляет длину сообщения перед самим сообщением. Получатель читает длину сначала, а затем столько байтов, сколько говорит длина.
Отправитель отправляет уникальный terminator после каждого сообщения. Получатель читает до тех пор, пока не получен terminator.
Важно понимать, что нет 1:1 соотношения между отправкой и чтением на сокете TCP. Любая отдельная операция чтения может вернуть меньше байтов, чем запрошено, поэтому необходим цикл, чтобы убедиться, что все ожидаемые байты получены.
В втором случае необходим один цикл для чтения байтов длины сообщения, а затем другой цикл для чтения байтов самого сообщения.
Давайте рассмотрим примеры кода на Object Pascal (Delphi) для каждого из этих подходов.
Пример 1: Фиксированная длина сообщения
procedure FixedLengthMessage(var Socket: TSocket);
var
Buffer: array[0..1023] of Byte;
BytesRead: Cardinal;
begin
SetLength(Buffer, 1024);
BytesRead := 0;
while BytesRead < 1024 do
begin
BytesRead := BytesRead + ReceiveSocket(Socket, @Buffer[BytesRead], 1024 - BytesRead, 0);
end;
// Обработка полученного сообщения
end;
Пример 2: Отправка длины сообщения
procedure LengthPrefixedMessage(var Socket: TSocket);
var
LengthBuffer: array[0..3] of Byte;
MessageBuffer: array[0..1023] of Byte;
Length: Cardinal;
BytesRead: Cardinal;
begin
BytesRead := ReceiveSocket(Socket, @LengthBuffer[0], 4, 0);
Length := (LengthBuffer[0] shl 24) or (LengthBuffer[1] shl 16) or (LengthBuffer[2] shl 8) or LengthBuffer[3];
SetLength(MessageBuffer, Length);
BytesRead := 0;
while BytesRead < Length do
begin
BytesRead := BytesRead + ReceiveSocket(Socket, @MessageBuffer[BytesRead], Length - BytesRead, 0);
end;
// Обработка полученного сообщения
end;
Пример 3: Уникальный terminator
procedure TerminatorDelimitedMessage(var Socket: TSocket);
var
Buffer: array[0..1023] of Byte;
BytesRead: Cardinal;
Terminator: array[0..2] of Byte;
begin
SetLength(Buffer, 1024);
SetLength(Terminator, 3);
BytesRead := 0;
while BytesRead < 1024 do
begin
BytesRead := BytesRead + ReceiveSocket(Socket, @Buffer[BytesRead], 1024 - BytesRead, 0);
if CompareMem(@Buffer[BytesRead - 3], @Terminator[0], 3) = 0 then
Break;
end;
// Обработка полученного сообщения
end;
В каждом из этих примеров мы используем цикл, чтобы гарантировать получение всех ожидаемых байтов. Важно выбрать подход, который лучше всего подходит для вашего конкретного использования протокола TCP.
В данном контексте рассматриваются три подхода к определению полного приема сообщения в протоколе TCP: фиксированная длина сообщения, отправка длины сообщения и уникальный terminator, с примерами кода на Object Pascal (Delphi) для каждого из эти
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS