Текущий архив: 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.49 MB
Время: 0.022 c