Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Разбор заголовка и пакетов. [D7, WinXP]


MikeLevin ©   (2007-07-26 22:40:00) 

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

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

hdr_ident = Byte
hdr_crc  = Word
hdr_len  = Word

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


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

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

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

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

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

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

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

Спасибо.


SlymRO   (2007-07-27 12:32:00) [1]

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

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


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


> зачем это?


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

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


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


Именно так.

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


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

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


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


> p: PByte;


> Packet: PPacket;


> p := Packet;


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


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


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


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


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

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

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 08:13:00) [7]


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


А зачем ?

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


SlymRO   (2007-07-27 06:33:00) [8]

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;


SlymRO   (2007-07-27 06:15:00) [9]

Использовать массив/список буферов типа...
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(


Наверх

Титульная страница Поиск, карта сайта Написать письмо