Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.04.27;
Скачать: CL | DM;

Вниз

Разбор заголовка и пакетов.   Найти похожие ветки 

 
MikeLevin   (2007-07-26 22:40) [0]

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

Есть некоторый собственный бинарный протокол (TCP) у котрого есть заголовок приблизительно такой.

hdr_ident = Byte
hdr_crc  = Word
hdr_len  = Word

далее сам пакет, размером hdr_len


Где первый байт - просто обозначение начала нового пакета, след. word - контрольная сумма, а последний word - это длина всего пакета не включая размер этого заголовка.

Так вот, при событии на поступления данных (в TWSocket), забираю все принятые данные из сокета. Но вот тут я и не знаю, пакеты могут скеливаться и расщепляться и как и куда их писать в какой буфер, не знаю.

Например ситуация, когда сначало получен только заголовок и часть данный, это понятно. Но вот как действовать когда приходят например сразу два полных пакета и третий не полный.

Для простого случая действую так:

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

А вот какого типа лучше использовать буфер, что бы если пришло несколько пакетов, можно было лекго удалить первый пакет, сместив в начало неполный пакет.

Может у кого есть собственный код, пример, что бы мне понять было легче, как действовать.

Спасибо.


 
SlymRO ©   (2007-07-27 06:15) [1]

Использовать массив/список буферов типа...
TPacketHeader=packed record
 hdr_ident:Byte;
 hdr_crc:Word;
 hdr_len:Word;
end;
PPacket=^TPacket;
TPacket=packed record
 Header:TPacketHeader;
 Data:pointer;
end;
TPacketArray:array[0..0] of PPacket;

read(Packet.Header,SizeOf(TPacketHeader));
read(


 
SlymRO ©   (2007-07-27 06:33) [2]

TPacket=packed record
Header:TPacketHeader;
Readed:Word;
Data:pointer;
end;

Packet:=New(PPacket);
Packet.Readed:=0;
read(Packet.Header,SizeOf(TPacketHeader));
GetMem(Packet.Data,Packet.hdr_len);
Packet.Readed:=read(poinder(dword(Packet.Data)+Packet.Readed),Packet.hdr_len-Packet.Readed);
if Packet.Readed<Packet.hdr_len then dokachka;

finally
 if Packet.Data<>nil then
   FreeMem(Packet.Data,Packet.hdr_len);
 Dispose(Packet)
end;


 
Сергей М. ©   (2007-07-27 08:13) [3]


> при событии на поступления данных (в TWSocket), забираю
> все принятые данные


А зачем ?

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


 
Сергей М. ©   (2007-07-27 09:06) [4]

Упрощенный пример реализации сабжа на основе машины состояния:

type
 TReadState = (rsHeader, rsData);

 TPacketHeader = packed record
    ...
    Len: Word;
    ...
  end;

  PPacket = ^TPacket;
  TPacket = packed record
    Header: TPacketHeader;
    Data: record end;
  end;

var
  State: TReadState = rsHeader;
  Packet: PPacket;
  BytesNeed: Integer;

...

 procedure TSomeClass.DoOnReceivedDataAvailable(..);
 var
   BytesReceived: Integer;
   i: Integer;
   p: PByte;
 begin
   case State of
    rsHeader:
      begin
         if not Assigned(Packet) then begin
           Packet := SysGetMem(SizeOf(TPacketHeader));
           BytesNeed := SizeOf(TPacketHeader);
         end;
         p := Packet;
         Inc(p, SizeOf(TPacketHeader) - BytesNeed);
         BytesReceived := Read(p^, BytesNeed);          
         Dec(BytesNeed, BytesReceived) ;
         if BytesNeed = 0 then begin
            BytesNeed := Packet.Len - SizeOf(TPacketHeader);
            Packet := SysReallocMem(Packet, BytesNeed);
            State := rsData;
         end;
      end;
    rsData:
      begin
         p := Packet;
         Inc(p, p.Len - BytesNeed);
         BytesReceived := Read(p^, BytesNeed);
         Dec(BytesNeed, BytesReceived) ;
         if BytesNeed = 0 then begin
            BytesNeed := SizeOf(TPacketHeader);
            State := rsHeader;
            DoNewpacketReceived(Packet); //обработка принятого пакета
            SysFreeMem(Packet);
            Packet := nil;
         end;
      end;
   end;
 end;


 
Сергей М. ©   (2007-07-27 09:11) [5]


>    Inc(p, p.Len - BytesNeed);


Inc(p, p.Header.Len - BytesNeed);


 
MikeLevin   (2007-07-27 12:19) [6]


> p: PByte;


> Packet: PPacket;


> p := Packet;


Хммм... зачем это?


 
MikeLevin   (2007-07-27 12:21) [7]

И ещё вопрос, все же есть какие то рекомендации, когда следует получать целиком сразу все принятые данные, а когда получать их кусочками по размеру заголовка? или это всё дело вкуса?


 
Сергей М. ©   (2007-07-27 12:30) [8]


> зачем это?


Просто для наглядности работы алгоритма.

Следующим Inc-оператором указатель p инкрементируется так чтобы он указывал на актуальную позицию записи в буфере (рассматриваемом при этом просто как блок байт), распределенном под TPacket


> это всё дело вкуса?


Именно так.

Но создавать себе лишние проблемы, читая без разбора все имеющиеся данные и затем делить их на пакеты, imho, дело дурного вкуса)


 
SlymRO ©   (2007-07-27 12:32) [9]

MikeLevin   (27.07.07 12:21) [7]
получать целиком сразу все принятые данные

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



Страницы: 1 вся ветка

Текущий архив: 2008.04.27;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.016 c
15-1205433311
Dr.Andrew
2008-03-13 21:35
2008.04.27
Ошибка при инсталляции Delphi 2007! Как исправить?


15-1205272268
No_Dead
2008-03-12 00:51
2008.04.27
От нечего делать, или Квадрат Дюрера%>


15-1202555449
md10
2008-02-09 14:10
2008.04.27
Пропадает HDD


2-1207164129
Gringoire
2008-04-02 23:22
2008.04.27
Часы с отображением дня недели и названием месяца.


6-1185475224
MikeLevin
2007-07-26 22:40
2008.04.27
Разбор заголовка и пакетов.