Автор: Alexander
Vaga WEB-сайт: http://icq2000cc.hobi.ru
Итак, рассмотрим механизм приема FLAP-пакетов. Прием пакетов - это обработчик
события onReadData нашего ClientSocket. Задача этого обработчика сводится только
к приему FLAP-пакетов и формировании из них связного списка типа FIFO (первым
пришел, первым и ушел). Главное корректно отработать границы пакетов.
Каждый пакет принимается в два захода:
- сначала принимаем только заголовок FLAP-пакета (всего 6 байт);
- затем, узнав из заголовка длину блока данных, принимаем последний (ни байтом
больше, ни байтом меньше).
Приняв полный пакет, формируем из него элемент списка FIFO и присоединяем его
к списку. Смотрим, как это сделано у меня. Для прима заголовка и блока данных
FLAP-пакета объявлены два массива: FLAP и FLAP_DATA соответственно.
procedure TForm1.CLI_ReadData(Sender:TObject; Socket:TCustomWinSocket); var num,Bytes,fact : integer; pFIFO,CurrFIFO : PFLAP_Item; buf : array[0..100] of byte; begin // узнаем, сколько всего данных уже есть в буфере ClientSocketa num := Socket.ReceiveLength; // в icq_Login мы установили isHdr, т.к. сначала ожидаем заголовок if isHDR then begin // если есть как минимум 6 байт, то читаем 6 байт заголовка в FLAP if num>=6 then begin Socket.ReceiveBuf(FLAP,6); // из заголовка узнаем длину блока данных FLAP-пакета NeedBytes := swap(FLAP.Len); // сбрасываем в начало индекс массива FLAP_DATA index := 0; // сбпасываем, чтобы следующее чтение было в FLAP_DATA // и выходим из обработчика isHDR := false; end else begin // вообще-то ситуация, когда в Sockete меньше 6-и байт // пока никак не контролируется (возникает очень редко :) // отмечаю этот факт только в окне отладки M(Memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); Socket.ReceiveBuf(buf,num); M(Memo,Dim2Hex(@(buf),num)); M(Memo,'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); end;
// if not isHDR then чтение в FLAP_DATA end else begin // сколько байт читать уже известно: NeedBytes Bytes := NeedBytes; // читаем их в FLAP_DATA[Index] fact := Socket.ReceiveBuf(FLAP_DATA[index],Bytes); // если в Sockete было данных меньше чем нужно, // педвинем Index и NeedBytes для следующего входа в обработчик inc(index,fact); dec(NeedBytes,fact); if NeedBytes = 0 then begin // если весь блок данных FLAP-пакета уже в FLAP_DATA, // тогда выделаем память для элемента списка FIFO (PFLAP_Item) New(pFIFO); // копируем заголовок pFIFO^.FLAP := FLAP; pFIFO^.Next := nil; // выделяем память для блока данных и копируем его GetMem(pFIFO^.DATA,index); move(FLAP_DATA,PFIFO^.Data^,swap(FLAP.Len)); // добавляем указатель на PFLAP_Item в список CurrFIFO:=HeadFIFO; if HeadFIFO<>nil then begin while CurrFIFO<>nil do if CurrFIFO^.Next=nil then begin CurrFIFO^.Next:=pFIFO; break; end else CurrFIFO:=CurrFIFO^.Next; end else HeadFIFO:=pFIFO; // устанавливаем isHDR (в true) уже для прима заголовка // последующих FLAP-пакетов isHDR := true; end; end; end;
|
Дальнейшая обработка списка FIFO - это задача уже другой процедуры. |