Indy, как узнать размер необходимого буфера? - PullRequest
3 голосов
/ 04 марта 2011

У меня есть некоторые проблемы при использовании Indy ( idTCPServer компонент) для чтения данных, отправленных клиентом, сами данные были отформатированы в шестнадцатеричном формате, поэтому я не могу использовать AThread.Connection.ReadLn (); для этого ...

Здесь мои образцы данных отправлены клиентом

24 24 00 11 12 34 56 FF FF FF FF 50 00 8B 9B 0D 0A

или

24 24 00 13 12 34 56 FF FF FF FF 90 02 00 0A 8F D4 0D 0A

PS : этов байтах шестнадцатеричный (длина данных может варьироваться в зависимости от команды, максимум 160 байт ), который я не могу получить строковое представление, так как $ 00 переведен в ноль (что означает, что я не могу использовать ReadLn)

Вот мой пример кода

procedure TfrmMain.IdTCPServerExecute(AThread: TIdPeerThread);
var
  Msg : Array[0..255] of Byte;
begin      
  AThread.connection.ReadBuffer(Msg,SizeOf(Msg));
  AThread.connection.WriteBuffer(Msg,MsgSize,true);
end;

этот код не будет работать, если клиент не отправит 255-байтовые данные, в то время как в моем случае длина данных может изменяться, я пробовал это, но ответ не выводился

procedure TfrmMain.IdTCPServerExecute(AThread: TIdPeerThread);
var
  Msg : Array of Byte;
  MsgSize : integer;
begin  
  MsgSize := AThread.connection.ReadInteger; //doesn't actually get packet length?
  SetLength(Msg, MsgSize);    
  AThread.connection.ReadBuffer(Msg,MsgSize);
  AThread.connection.WriteBuffer(Msg,MsgSize,true);
end;

так как именно я могу посчитать, сколько байтовых данных отправлено клиентом (длина пакета)?или кто-то может сказать мне правильный код для чтения данных?

Ответы [ 2 ]

4 голосов
/ 04 марта 2011

Простой ответ: Вы не можете . TCP - это протокол stream , поэтому концепция сообщения отсутствует. Данные принимаются порциями, размеры которых могут (и будут) отличаться от фактически отправленных буферов (сетевой стек может свободно разделять или объединять поток по желанию).
Вы можете создать протокол сообщений поверх TCP, например, начиная передачу и каждое последующее сообщение посредством «поля размера», а затем ожидая только необходимые байты; Вам все еще нужно проверить фактический полученный размер и перечитать остальные, если применимо.

Дело в том, что длина пакета в мире TCP не имеет отношения к длине отправленных сообщений .
Что TIdTCPConnection делает за всеми Read -методами:
чтение всех доступных данных из сетевого стека, добавление их во внутренний входной буфер и возвращение запрошенных N байтов из начала буфера, если доступно (ожидание следующего фрагмента, если нет).

3 голосов
/ 05 марта 2011

3-й и 4-й байты в показанных вами данных указывают общий размер отправляемых данных. Вы были близки к тому, чтобы попробовать ReadInteger(), но способ, которым вы его использовали, включает в себя 1-й и 2-й байты, что неправильно. Попробуйте вместо этого:

procedure TfrmMain.IdTCPServerExecute(AThread: TIdPeerThread);
var
  Unknown: Smallint; // maybe a msg type?
  DataSize: Smallint;
  Data: Array of Byte;
begin
  Unknown := AThread.Connection.ReadSmallInt;
  DataSize := AThread.Connection.ReadSmallInt - 4;
  SetLength(Data, DataSize);
  AThread.Connection.ReadBuffer(Data[0], DataSize);
  //...
end;
...