Thema: Socket C&S

Einzelnen Beitrag anzeigen

Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#24

AW: Socket C&S

  Alt 9. Feb 2018, 23:31
So in etwa würde ich vorgehen, um direkt nach dem Connecten einen simplen String an den Server zu schicken (btw. die Socket Komponenten sind schon sehr lange deprecated und evtl. könnten blocking Sockets hier für dich auch besser geeignet sein):
Delphi-Quellcode:
unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Win.ScktComp;

type
  TSocketBufferDataEvent =
    procedure (Sender: TOBject; Socket: TCustomWinSocket; const Data: TBytes) of Object;

  TSocketBuffer = class(TObject)
  strict private
    FBuffer: TMemoryStream;
    FLength: UInt32;
  strict private
    FOnData: TSocketBufferDataEvent;
  public
    procedure Receive(Socket: TCustomWinSocket);
  public
    constructor Create;
    destructor Destroy; override;
  public
    property OnData: TSocketBufferDataEvent read FOnData write FOnData;
  end;

  TForm2 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  strict private
    FClient: TClientSocket;
    FClientBuffer: TSocketBuffer;
    FServer: TServerSocket;
  strict private
    procedure Send(Socket: TCustomWinSocket; const Data: TBytes);
  strict private
    procedure ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientData(Sender: TOBject; Socket: TCustomWinSocket; const Data: TBytes);
    procedure ServerClientConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure ServerClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure ServerRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure ServerData(Sender: TOBject; Socket: TCustomWinSocket; const Data: TBytes);
  public
    { Public-Deklarationen }
  end;

var
  Form2: TForm2;

implementation

uses
  System.Math;

{$R *.dfm}

{ TSocketBuffer }

constructor TSocketBuffer.Create;
begin
  inherited Create;
  FBuffer := TMemoryStream.Create;
  FLength := 0;
end;

destructor TSocketBuffer.Destroy;
begin
  FBuffer.Free;
  inherited;
end;

procedure TSocketBuffer.Receive(Socket: TCustomWinSocket);
type
  PUInt32 = ^UInt32;
var
  B: array[0..64*1024 - 1] of Byte;
  N: UInt32;
  D: TBytes;
begin
  // Erstmal alle Daten in den Buffer schreiben
  while (Socket.ReceiveLength > 0) do
  begin
    N := System.Math.Min(Socket.ReceiveLength, Length(B));
    Socket.ReceiveBuf(B[0], N);
    FBuffer.Write(B[0], N);
    Inc(FLength, N);
  end;

  // Pakete parsen
  while (FLength >= SizeOf(N)) do
  begin
    N := PUInt32(FBuffer.Memory)^;
    if (FLength < SizeOf(N) + N) then
    begin
      Break;
    end;
    // Mindestens ein Paket vollständig angekommen
    SetLength(D, N);
    CopyMemory(@D[0], PByte(FBuffer.Memory) + SizeOf(N), N);
    if Assigned(FOnData) then
    begin
      FOnData(Self, Socket, D);
    end;

    // Jetzt muss das bearbeitete Paket aus dem Buffer "entfernt" werden
    CopyMemory(FBuffer.Memory, PByte(FBuffer.Memory) + SizeOf(N) + N, FLength - SizeOf(N) - N);
    Dec(FLength, SizeOf(N) + N);
    FBuffer.Position := FBuffer.Position - SizeOf(N) - N;
  end;
end;

{ TForm2 }

procedure TForm2.Button1Click(Sender: TObject);
begin
  FClient.Active := true;
end;

procedure TForm2.ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Send(Socket, TEncoding.UTF8.GetBytes('This is a test string'));
end;

procedure TForm2.ClientData(Sender: TOBject; Socket: TCustomWinSocket; const Data: TBytes);
begin
  // Vollständiges Paket vom Server empfangen

end;

procedure TForm2.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
begin
  FClientBuffer.Receive(Socket);
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  FClient := TClientSocket.Create(Self);
  FClient.ClientType := ctNonBlocking;
  FClient.Host := 'localhost';
  FClient.Port := 12345;
  FClient.OnConnect := ClientConnect;
  FClient.OnRead := ClientRead;
  FClientBuffer := TSocketBuffer.Create;
  FClientBuffer.OnData := ClientData;
  FServer := TServerSocket.Create(Self);
  FServer.ServerType := stNonBlocking;
  FServer.Port := 12345;
  FServer.OnClientConnect := ServerClientConnect;
  FServer.OnClientDisconnect := ServerClientDisconnect;
  FServer.OnClientRead := ServerRead;
  FServer.Active := true;
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  FClientBuffer.Free;
end;

procedure TForm2.Send(Socket: TCustomWinSocket; const Data: TBytes);
var
  N, S: UInt32;
begin
  N := Length(Data);
  S := 0;
  Assert(Socket.SendBuf(N, SizeOf(N)) = 4);
  while (S < N) do
  begin
    Inc(S, Socket.SendBuf(Data[S], N - S));
  end;
end;

procedure TForm2.ServerClientConnect(Sender: TObject; Socket: TCustomWinSocket);
var
  Buffer: TSocketBuffer;
begin
  Buffer := TSocketBuffer.Create;
  Buffer.OnData := ServerData;
  Socket.Data := Buffer;
end;

procedure TForm2.ServerClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  TSocketBuffer(Socket.Data).Free;
end;

procedure TForm2.ServerData(Sender: TOBject; Socket: TCustomWinSocket; const Data: TBytes);
begin
  // Vollständiges Paket vom Client empfangen
  Caption := TEncoding.UTF8.GetString(Data);
end;

procedure TForm2.ServerRead(Sender: TObject; Socket: TCustomWinSocket);
begin
  TSocketBuffer(Socket.Data).Receive(Socket);
end;

end.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat