Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Приём и обработка пакетов переданных методом SendText - с учётом склеенных и полученных неполностью пакетов

Автор: VID
WEB-сайт: http://delphibase.endimus.com

{ **** UBPFD *********** by delphibase.endimus.com ****
>> Приём и обработка пакетов переданных методом SendText() -
с учётом "склеенных" и полученных неполностью пакетов.

Юнит RecvPckt предназначен для приёма текста, передаваемого с помощью метода SendText
объекта Socket:TCustomWinSocket. Данный юнит может использоваться как клиентом так
и сервером для обработки принятого пакета.

Функции данного юнита предусматривают возможность получения "склеенных" пакетов,
или пакетов, пришедших не полностью.

Тип TBuffer;
FBuffer - хранит в себе принимаемый пакет
FCurrentPacketSize = храни сведения о полной длине пакета.

Описание функций и процедур, необходимых для использования в других юнитах

Procedure ClearBuffer(var ABuffer:TBuffer);
Очищает буффер FBuffer и обнуляет значение FCurrentPacketSize;

Function ProcessReceivedPacket(var ABuffer:TBuffer; var APacket:String):Boolean;
В данную функцию передаётся полученный от клиента/сервера пакет, через аргумент APacket
Принцип работы этой функции заключается в накоплении получаемого текста в поле
FBuffer объекта ABuffer. В случае когда FBuffer будет содержать полностью весь пакет,
функция возвратит True, иначе возвращает False

Функция ОТПРАВКИ текста:
Function SendTextToSocket(Socket:TCustomWinSocket; Text:String):Integer;
Var S:String;
begin
Result := -1;
IF Text = '' then exit;
IF Socket.Connected then
begin
S:=IntToStr(Length(Text));
Result := Socket.SendText(S+'#'+Text);
end;
end;

Зависимости: sysutils
Автор:       VID, snap@iwt.ru, ICQ:132234868, Махачкала
Copyright:   VID
Дата:        30 сентября 2002 г.
***************************************************** }

unit RecvPckt;

interface

uses
  SysUtils;

type
  TReadHeaderResult = record
    FPacketSize: Integer;
    FPacketSizeStr: string;
    FTextStartsAt: Integer;
  end;

type
  TBuffer = record
    FBuffer: string;
    FHeaderBuffer: string;
    FCurrentPacketSize: Integer;
  end;

procedure ClearBuffer(var ABuffer: TBuffer);
function ReadHeader(var ABuffer: TBuffer; var APacket: string):
  TReadHeaderResult;
function ProcessReceivedPacket(var ABuffer: TBuffer; var APacket: string):
  Boolean;

implementation

procedure ClearBuffer(var ABuffer: TBuffer);
begin
  ABuffer.FBuffer := '';
  ABuffer.FHeaderBuffer := '';
  ABuffer.FCurrentPacketSize := 0;
end;

function ReadHeader(var ABuffer: TBuffer; var APacket: string):
  TReadHeaderResult;
var
  X, HBuffLen: Integer;
  procedure ClearHeader;
  begin
    ABuffer.FHeaderBuffer := '';
  end;

  function CorrectPacket: Boolean;
  var
    I, L: Integer;
  begin
    X := 0;
    L := Length(APacket);
    for I := 1 to L do
      if (APacket[I] in ['0'..'9']) then
        BREAK
      else if (APacket[I] = '#') and (ABuffer.FHeaderBuffer <> '') then
        BREAK
      else
        X := I;
    if X > 0 then
      Delete(APacket, 1, X);
    RESULT := APacket <> '';
  end;

  procedure GetHeader;
  var
    I, L: Integer;
  begin
    L := Length(APacket);
    X := 0;
    for I := 1 to L do
    begin
      X := I;
      if (APacket[I] in ['0'..'9']) then
      begin
        HBuffLen := Length(ABuffer.FHeaderBuffer);
        if HBuffLen > 0 then
          Inc(HBuffLen);
        Insert(APacket[I], ABuffer.FHeaderBuffer, HBuffLen);
      end
      else
        Break;
    end;
  end;

  procedure SetResultToNone;
  begin
    Result.FPacketSize := 0;
    Result.FTextStartsAt := 0;
    Result.FPacketSizeStr := '';
  end;

begin
  SetResultToNone;
  if APacket = '' then
    Exit;
  if ABuffer.FCurrentPacketSize > 0 then
  begin
    Result.FPacketSize := ABuffer.FCurrentPacketSize;
    Result.FPacketSizeStr := IntToStr(ABuffer.FCurrentPacketSize);
    Result.FTextStartsAt := 1;
    Exit;
  end;
  if not CorrectPacket then
    Exit;
  GetHeader;
  if APacket[X] = '#' then
  begin
    Inc(X);
    try
      Result.FPacketSize := StrToInt(ABuffer.FHeaderBuffer);
    except
    end;
    Result.FPacketSizeStr := ABuffer.FHeaderBuffer;
    ClearHeader;
  end
  else if not (APacket[X] in ['0'..'9']) then
    ClearHeader;
  Result.FTextStartsAt := X;
end;

function ProcessReceivedPacket(var ABuffer: TBuffer; var APacket: string):
  Boolean;
var
  ReadHeaderResult: TReadHeaderResult;
  NeedToCopy, DelSize: Integer;
  S: string;
  BuffLen: Integer;

  function FullPacket: Boolean;
  begin
    Result := Length(ABuffer.FBuffer) = ABuffer.FCurrentPacketSize;
  end;
begin
  Result := True;
  if APacket = '' then
    Exit;
  if ABuffer.FBuffer = '' then
  begin
    ReadHeaderResult := ReadHeader(ABuffer, APacket);
    ABuffer.FCurrentPacketSize := ReadHeaderResult.FPacketSize;
    S := Copy(APacket, ReadHeaderResult.FTextStartsAt,
      ReadHeaderResult.FPacketSize);
    DelSize := Length(ReadHeaderResult.FPacketSizeStr) +
      ReadHeaderResult.FPacketSize + 1;
  end
  else
  begin
    NeedToCopy := ABuffer.FCurrentPacketSize - Length(ABuffer.FBuffer);
    S := Copy(APacket, 1, NeedToCopy);
    DelSize := NeedToCopy;
  end;
  if ABuffer.FCurrentPacketSize > 0 then
  begin
    BuffLen := Length(ABuffer.FBuffer);
    if BuffLen > 0 then
      Inc(BuffLen);
    Insert(S, ABuffer.FBuffer, BuffLen);
  end;

  if not FullPacket then
    Result := False;
  if ABuffer.FHeaderBuffer = '' then
    DELETE(APacket, 1, DelSize)
  else
  begin
    APacket := '';
    Result := False;
  end;
end;

end.

Пример использования:

// Объявляем переменную типа TBuffer. Для каждого клиента на
// сервере должна быть объявлена отдельная переменная этого типа
var
  GBuffer: TBuffer;
...

procedure TForm1.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  S: string;
begin
  S := Socket.ReceiveText;
  repeat
    if ProcessReceivedPacket(GBuffer, S) then
    begin
      if GBuffer.FBuffer <> '' then
        Recv.Lines.Add(GBuffer.FBuffer);
      //или же передать GBuffer.FBuffer на исполнение.
      ClearBuffer(GBuffer);
    end;
  until S = '';
end;
Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay