Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Приём и обработка пакетов переданных методом SendText - с учётом склеенных и полученных неполностью пакетов

Delphi , Интернет и Сети , Сокеты

Приём и обработка пакетов переданных методом 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;

Единица RecvPckt предназначена для приема и обработки пакетов, отправленных клиентом с помощью метода SendText объекта TCustomWinSocket. Единица предоставляет два основные функции: ProcessReceivedPacket и ReadHeader.

Функция ProcessReceivedPacket Эта функция принимает буфер (ABuffer) и пакет (APacket) в качестве входных параметров и возвращает логическое значение, указывающее, является ли пакет полным или нет. Функция аккумулирует полученный текст в поле FBuffer буфера. Если буфер содержит полный пакет (т. е. его длина равна текущему размеру пакета), функция устанавливает Result в True. В противном случае она устанавливает Result в False.

Функция ReadHeader Эта функция читает заголовок входящего пакета и извлекает размер пакета и позицию начала текста. Функция принимает буфер (ABuffer) и пакет (APacket) в качестве входных параметров и возвращает запись TReadHeaderResult, содержащую размер пакета, строку размера пакета и позицию начала текста.

Процедура ClearBuffer Эта процедура очищает буфер, устанавливая поля его в пустые строки и сбрасывая текущий размер пакета до 0.

Единица также предоставляет несколько процедур и функций для обработки входящих пакетов:

  • GetHeader: извлекает заголовок из входящего пакета
  • SetResultToNone: устанавливает результат функции ReadHeader в None (т. е. очищает его поля)
  • CorrectPacket: проверяет, является ли пакет корректным, сравнивая его с цифрами или символом #

Единица может использоваться в сочетании с другими единицами, предоставляющими функциональность для общения по сокетам. Например, вы можете создать сервер, слушающий входящие соединения, и использовать единицу RecvPckt для приема и обработки пакетов от клиентов.

Вот пример использования этой единицы:

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); // или выполните полученный текст
      ClearBuffer(GBuffer);
    end;
  until S = '';
end;

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

Программное обеспечение для приема и обработки пакетов текста, передаваемых методом SendText, с учетом склеенных и полученных неполностью пакетов.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Сокеты ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-19 13:29:56
2024-11-21 11:58:34/0.0063490867614746/1