Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi 2 UDP server auf demselben Port ? (https://www.delphipraxis.net/90008-2-udp-server-auf-demselben-port.html)

th_bone 10. Apr 2007 12:41


2 UDP server auf demselben Port ?
 
Hi,

gibt es einen Weg 2 UDP server (auf einem Rechner) zu erlauben über den selben Port lauschen ?

Hintergrund: ich möchte mit einem Steuerprogramm verschiedene Programme per UDP broadcast
ansprechen... das funktioniert ja soweit auch ohne Probleme - aber sobald die Programme auf demselben
Rechner sind, dann kann nur jeweils ein UDP server auf den Port connected werden...

Wie löst ihr sowas ? Da es häufig dieselben Daten sind wollte ich eigentlich nicht verschiedene Ports nutzen,
da ich ja sonst den Trafffic künstlich erhöhe...

Danke

Ralf

Klaus01 10. Apr 2007 12:48

Re: 2 UDP server auf demselben Port ?
 
Zwei Server die auf einem Port lauschen ist meines Wissens nicht möglich.
Ist es nicht möglich, das der eine Server die Daten zum zweiten Server weiterreicht?

Grüße
Klaus

SirThornberry 10. Apr 2007 13:07

Re: 2 UDP server auf demselben Port ?
 
ein Port steht in der Regel für einen Service. Dementsprechend sollten verschiedene Dienste (Programme die verschiedenes machen) auch auf verschiedenen Ports laufen. Und wenn Programm auf einem Rechner miteinander kommunizieren sollen gibt es andee Lösungen wie pipes, messages etc.

joachimd 10. Apr 2007 13:12

Re: 2 UDP server auf demselben Port ?
 
Zitat:

Zitat von th_bone
gibt es einen Weg 2 UDP server (auf einem Rechner) zu erlauben über den selben Port lauschen ?

Du darfst den Port nicht exklusiv binden. Ich habe mal sowas für die Notification in ADS in eine Komponente (Komponente kapselt einen Empfangs-Thread) gepackt. Die kannst Du Dir für Deine Zwecke abändern. Verantwortlich ist in CreateSocket das SO_REUSEADDR.
Delphi-Quellcode:
unit AdsNotify;

interface

uses
  SysUtils, Classes, winsock, windows;

type

  ESocketError = class(EOSError);
  TrcLog = procedure(s:string) of object;
  TrcNotifyEvent = procedure (Sender:TObject;tables:string) of object;

  TReceiveThread = class(TThread)
  private
    { Private declarations }
    fPort:integer;
    FOnReceive: TrcNotifyEvent;
    FOnLog: TrcLog;
    procedure SetOnLog(const Value: TrcLog);
    procedure SetOnReceive(const Value: TrcNotifyEvent);
  protected
    procedure Execute; override;
    procedure DoReceive;
    procedure Log(s:string);
  public
    msg:string;
    constructor Create(Port:integer);
    property OnReceive:TrcNotifyEvent read FOnReceive write SetOnReceive;
    property OnLog:TrcLog read FOnLog write SetOnLog;
  end;

  tAdsNotify = class(TComponent)
  private
    FPort: integer;
    FOnNotification: TrcNotifyEvent;
    rcThread:TReceiveThread;
    procedure SetPort(const Value: integer);
    procedure SetOnNotification(const Value: TrcNotifyEvent);
    { Private declarations }
  protected
    { Protected declarations }
    procedure DoNotification;
  public
    { Public declarations }
    constructor Create(Owner:TComponent; Port:integer=0); reintroduce;
  published
    { Published declarations }
    property Port:integer read FPort write SetPort;
    property OnNotification:TrcNotifyEvent read FOnNotification write SetOnNotification;
  end;

resourcestring
  SSocketError = 'Socket Error. Code: %d.' + sLineBreak + '%s';
  SUnkSocketError = 'A call to a socket function failed';

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Advantage', [tAdsNotify]);
end;

{ tAdsNotify }

constructor tAdsNotify.Create(Owner: TComponent; Port: integer=0);
begin
  inherited Create(Owner);
  rcThread:=nil;
  SetPort(Port);
end;

procedure tAdsNotify.DoNotification;
var
  tables:string;
begin
  if assigned(rcThread)
    then begin
      tables:=rcThread.msg;
      rcthread.msg:='';
      if assigned(FOnNotification)
      then FOnNotification(self,tables);
    end;
end;

procedure tAdsNotify.SetOnNotification(const Value: TrcNotifyEvent);
begin
  FOnNotification := Value;
  if assigned(rcThread)
    then rcThread.OnReceive:=OnNotification;
end;

procedure tAdsNotify.Setport(const Value: integer);
begin
  if assigned(rcThread)
    then begin
      rcThread.Terminate;
    end;
  Fport := Value;
  if FPort>0
    then begin
      rcThread:=TReceiveThread.Create(FPort);
      rcThread.OnReceive:=OnNotification;
      rcThread.FreeOnTerminate:=true;
      rcThread.Resume;
    end;
end;

{ TReceiveThread }

procedure RaiseSocketError(E: Integer);
var
  Error: ESocketError;
begin
  if E <> 0 then
    Error := ESocketError.CreateResFmt(@SSocketError, [E, SysErrorMessage(E)])
  else
    Error := ESocketError.CreateRes(@SUnkSocketError);
  Error.ErrorCode := E;
  raise Error;
end;

procedure RaiseLastSocketError;
begin
  RaiseSocketError(WSAGetLastError);
end;

procedure InitWinSock;
var
  Data: TWSAData;
  E: Integer;
begin
  E := WSAStartup(1, Data);
  if E <> 0 then
    RaiseSocketError(E);
end;

function MachineName: String;
var
  Buf: array[0..MAX_COMPUTERNAME_LENGTH] of Char;
  Len: Cardinal;
begin
  Len := SizeOf(Buf);
  if GetComputerName(Buf, Len) then
    SetString(Result, Buf, Len)
  else
    Result := '?';
end;


function CreateSocket(port:integer):TSocket;
var
  Sock: TSocket;
  Opt: Integer;
  LocalAddr:TSockAddr;
begin
  InitWinSock;
  Sock := socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if Sock = INVALID_SOCKET then
    RaiseLastSocketError;
  Opt := 1;
  if setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, @Opt, SizeOf(Opt)) <> 0 then
    RaiseLastSocketError;
  LocalAddr.sin_family := AF_INET;
  LocalAddr.sin_port := htons(port);
  LocalAddr.sin_addr.S_addr := INADDR_ANY;
  if bind(Sock, LocalAddr, SizeOf(LocalAddr)) <> 0 then
    RaiseLastSocketError;
  result:=sock;
end;

function Receive(var Sock:TSocket;var s:string;var PeerAddr:TSockAddr):boolean;
var
  PeerAddrLen: Integer;
  MsgBuf: array[0..511] of Char;
  MsgLen: Integer;
begin
  PeerAddrLen := SizeOf(PeerAddr);
  MsgLen := recvfrom(Sock, MsgBuf, SizeOf(MsgBuf), 0, PeerAddr, PeerAddrLen);
  if MsgLen>0
    then begin
      SetString(s, MsgBuf, MsgLen);
      result:=true;
    end
    else begin
      result:=false;
    end;
end;




constructor TReceiveThread.Create(Port: integer);
begin
  inherited Create(true);
  fPort:=Port;
end;

procedure TReceiveThread.DoReceive;
begin
  if assigned(FOnReceive)
    then begin
      FOnReceive(self, msg);
      msg:='';
    end;
end;

procedure TReceiveThread.Execute;
var
  Sock: TSocket;
  PeerAddr: TSockAddr;
  PeerAddrLen: Integer;
  MsgBuf: array[0..511] of Char;
  MsgLen: Integer;
begin
  try
    Sock:=CreateSocket(fport);
    while not Suspended do
      begin
        PeerAddrLen := SizeOf(PeerAddr);
        MsgLen := recvfrom(Sock, MsgBuf, SizeOf(MsgBuf), 0, PeerAddr, PeerAddrLen);
        if MsgLen > 0
          then begin
            SetString(msg, MsgBuf, MsgLen);
            DoReceive;
          end;
      end;
  except
    on E:Exception do log(e.Message);
  end;
end;

procedure TReceiveThread.Log(s: string);
begin

end;

procedure TReceiveThread.SetOnLog(const Value: TrcLog);
begin
  FOnLog := Value;
end;

procedure TReceiveThread.SetOnReceive(const Value: TrcNotifyEvent);
begin
  FOnReceive := Value;
end;

end.

th_bone 10. Apr 2007 19:30

Re: 2 UDP server auf demselben Port ?
 
@SirThornberry - beim lauschen auf einem Port macht das bei UDP-Broadcast schon Sinn, wenn die Programme dieselben Ausgangsdaten benötigen, dann reicht ein Broadcast um verschiedene Programme zu bedienen - und der Vorteil ist, dass
es dann auch egal ist ob die Progs jetzt auf einem oder auf verschiedenen Rechnern im Netz laufen -

@Klaus01 - mehrere UDP-Server die auf einem Port lauschen sind möglich z.B. die ICS TWSocket - Komponente hat
wie ich gerade hearugefunden habe eine Eigenschaft "ReuseAddr" bei True funktioniert das ausgezeichnet..

@joachimd - danke für den Code, da muß ich mich erst mal reindenken

Die Frage die bleibt ist, ob es nicht doch möglich ist, dass auch über die Indys zu realisieren... habe
aber leider noch nicht den richtigen Schalter gefunden... und die Doku zu den Indys incl. Indy in "Depth" ist leider sehr
oberflächlich..

Schönen Abend

Ralf

joachimd 11. Apr 2007 08:04

Re: 2 UDP server auf demselben Port ?
 
Zitat:

Zitat von th_bone
Die Frage die bleibt ist, ob es nicht doch möglich ist, dass auch über die Indys zu realisieren... habe
aber leider noch nicht den richtigen Schalter gefunden... und die Doku zu den Indys incl. Indy in "Depth" ist leider sehr
oberflächlich..

IIRC geht das mit den Indy-Komponenten nicht, da es dort nicht als Property herausgeführt ist. Ich hatte mal eine Diskussion mit Hadi und Kudzu darüber und ihnen dann (auch nach Anfrage in den NG) das obige Beispiel gezeigt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:45 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz