Текущий архив: 2007.01.14;
Скачать: CL | DM;
Вниз
TWSocket разбор принятых пакетов Найти похожие ветки
← →
цыц (2006-08-16 17:53) [0]Есть некий протокол, header которого оформлен таким образом:
BByte, BSize, BNum, BCrc
CByte (Byte) - это начало пакета, неизменяемая константа.
PSize (Word) - размер всего пакета, не считая размера заголовка
BNum (Word) - номер пакета, инкрементируется
BCrc (DWord) - контрольная сумма начинки
В пакете, после заголовка идет начинка пакета. Требуется принять этот заголовок, узнать из него объем начинки и передать начинку на обработку в другую функцию.
Всё это дело осуществляется с помощью TWSocket (www.overbyte.be)
type
PHostHdr = ^THostHdr;
THostHdr = record
CByte: Byte;
PSize: Word;
BNum: Word;
BCrc: DWord;
end;
procedure WSocketOnDataAvailable(Sender: TObject; ErrCode: Word);
var
recvHeader: PHostHdr;
Count: integer;
begin
if Error <> 0 then begin
ShowMessage("Winsock error: " + IntToStr(Error));
Exit;
end;
Count := WSocket2.Receive(@recvHeader, 9);
if Count <= 0 then
Exit;
....
....
HLevelHandler(Наша начинка); // всё - обрабатываем в другой функции саму начинку.
end;
Вообщем, как это не глупо, но дальше я заглох. Я просто не знаю, что делать.
Считать заголовок, потом узнав из заголовка длину, сичтать весь пакет, но если пакет весь не успел дойти?
Вообщем нужен какой-то буфер, в который будут складываться пакеты. Нужно, что бы корректно всё обрабатывалось. Но я уже закипел просто.
Помогите пожалуйста, желательно с кодом.
← →
Ketmar © (2006-08-16 21:58) [1]код сам -- это полезно. тем более, что словами уже описано. заводишь флажок состояния (который показывает, что "в процессе": заголовок или данные). собираешь в буфер по получению. проверяешь, не пришёл ли полный пакет. если пришёл, разбираешь. всё.
← →
Ketmar © (2006-08-16 21:58) [2]тьфу. не надо никакого флажка. достаточно "убирать" разобраные пакеты из буфера. %-)
← →
цыц (2006-08-17 16:39) [3]Спасибо за совет, но я так и застрял на фазе воплощения этого совета в корректный код. Может ещё, чем поможете. Я пытался конструировать мысли так.
Я уже запутался, ну например заводим буфер. Заведомо больший, для ситуации если примется сразу несколько пакетов.
Затем мы забираем всё пришедшее из сокета в наш буфер.
Проверяем длину принятого, если <= 0, то выходим.
Читаем из буфера, наш заголовок.
Из заголовка читаем длину начинки пакета.
Проверяем условием Длина_заголовка_Начинки >= Длина_принятого_пакта - Длина_заголовка
Дальше не знаю... Но мне кажется, что я выбрал какой-то заведомо ложный путь.type
PHostHdr = ^THostHdr;
THostHdr = record
CByte: Byte;
PSize: Word;
BNum: Word;
BCrc: DWord;
end;
procedure WSocketOnDataAvailable(Sender: TObject; ErrCode: Word);
const
HEADER_LENGTH = 9;
var
recvHeader: PHostHdr;
Count: integer;
WSockBuffer: array [0..$ffff] of Byte;
begin
if Error <> 0 then begin
ShowMessage("Winsock error: " + IntToStr(Error));
Exit;
end;
Count := WSocket2.Receive(@WSockBuffer, SizeOf(WSockBuffer));
if Count <= 0 then
Exit;
WSockBuffer[Count] := $00;
recvHeader := @WSockBuffer[0];
if recvHeader^.DataLen >= Count - HEADER_LENGTH then
..............
end;
← →
Ketmar © (2006-08-17 16:53) [4]> [3] цыц (17.08.06 16:39)
> Дальше не знаю
ну дальше же очевидно. а у Вас баги. %-)
буфер не должен быть локальной переменной -- весь смысл буфера в том, чтобы хранить данные между вызовами OnDataAvailable(). равно как и счётчик заполненности буфера, кстати.
далее: когда пришёл весь пакет, забираем его из буфера. сдвигаем остаток буфера в начало (это Move() %-), исправляем count. и так далее.
зыж кстати, можно не делать огромный буфер, а просто не читать больше одного пакета. %-)
← →
Сергей М. © (2006-08-17 17:03) [5]
> Затем мы забираем всё пришедшее из сокета в наш буфер
А нахрена забирать все пришедшее ?
Забирай ровно столько, сколько осталось для заполнения текущей принимаемой структуры.
А то что не забрал - не пропадет, уверяю тебя)... Только не спрашивай почему - на то есть, цумбайшпиль, book.itep.ru
← →
цыц (2006-08-17 17:10) [6]
> зыж кстати, можно не делать огромный буфер, а просто не
> читать больше одного пакета. %-)
А можно чуть подробнее.
Я лучше всю схему понял при использовании флага: считываем из сокета длину заголовка, устанавливам флаг. Т.к. не все данные из сокета забрали (или они ещё не пришли), срабатывает во второй раз OnDataAvailable, и вот тут мы и считываем всю начинку из пакета по длине из заголовка и возвращаем флаг в обратное положение. И Дальше история повторяется с начала. Но хочется обойтись без заведения флага состояния.
← →
Ketmar © (2006-08-17 17:16) [7]> [6] цыц (17.08.06 17:10)
во-первых: никто тебе не гарантирует, что во второй раз ты прочитаешь ВСЁ. равно как и не гарантирует получение сразу всего заголовка. для этого и нужен буфер. теоретически возможна ситуация, когда пакет будет приодить по одному байту, например. ы?
а флагом у тебя уже работает счётчик заполненности буфера. по-совсместительству. %-)
← →
цыц (2006-08-17 17:34) [8]
> [7] Ketmar (17.08.06 17:16)
Ну вообщем я понял прелести буфера, но опять не понимаю некоторых вещей. Как мне уже выше посоветовали, считывать только заголовок, не делать огромный буфер.
OnDataAvailable: Забираю из сокета только заголовок если вдруг и он будет идти по частям? Как предусмотреть все ситуации и предусмотреть все возможные проблемы. Я запутался.
← →
DiamondShark © (2006-08-17 17:40) [9]
> если вдруг и он будет идти по частям?
забирать по 1 байту. меньше частей не бывает.
а как заголовок собрали, забирать тело.
Страницы: 1 вся ветка
Текущий архив: 2007.01.14;
Скачать: CL | DM;
Память: 0.47 MB
Время: 0.012 c