Entwickler-Ecke

Open Source Projekte - TUdpSockUtil v2.01 - Alternative zum Indy-UDP-Client/Server


Narses - Fr 03.02.06 02:29
Titel: TUdpSockUtil v2.01 - Alternative zum Indy-UDP-Client/Server
Der TUdpSockUtil ermöglicht die einfache Kommunikation über das UDP-Protokoll (UDP-Client/Server-Socket) und ist damit praktisch gleichwertig zu einem IdUdpServer und IdUdpClient in einer schlanken Komponente. Die Benutzung ist an TClientSocket bzw. TServerSocket angelehnt, so dass jemand, der gewohnt ist mit den Sockets umzugehen, keine großen Probleme damit haben sollte.
Die Komponente kann im Register "Internet" (da, wo normalerweise auch die Socket-Komponenten drin sind) installiert werden. Natürlich kann die Komponente auch dynamisch erzeugt werden, wenn die Installation in der IDE nicht gewünscht ist.

Grober Funktionsumfang:
Eine ausführliche Anleitung, wie man die Komponente installiert, sowie eine sehr ausführliche Dokumentation dieser und der Quelltext gleich mit, befindet sich im Projaktarchiv im Anhang. Neu: Dazu gibt es noch mehrere Beispielprogramm mit Source: Mini-UDP-Chat, UDP-Chat mit Flüstern, Micro-Controller Ansteuerung, AutoLocalPort-Demo.

In diesem Zusammenhang:
Wer ohne sich durch die Doku-Seiten "durchzuarbeiten" :les: :zwinker: wissen will, was diese Komponente "kann", sollte sich mal die fertige Demoprogramme im Projektarchiv ansehen bzw. ausprobieren, am besten auf mehreren PCs im LAN gleichzeitig. Hier ein Codebeispiel, um schon mal abschätzen zu können, wie einfach die Benutzung ist:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
uses
  ..., WinSock; // für den Typ in_addr

// Nachricht an den angegebenen Host senden
procedure TForm1.BtnSendClick(Sender: TObject);
begin
  UdpSockUtil1.RemoteHost := RemoteHost.Text;
  UdpSockUtil1.RemotePort := StrToIntDef(RemotePort.Text,12345);
  UdpSockUtil1.SendText(Input.Text);
end;

// Nachricht an alle Hosts im Netzwerk senden
procedure TForm1.BtnBroadcastClick(Sender: TObject);
begin
  UdpSockUtil1.RemotePort := StrToIntDef(RemotePort.Text,12345);
  UdpSockUtil1.BroadcastText(Input.Text);
end;

// Ereignis: Nachricht eingetroffen
procedure TForm1.UdpSockUtil1Receive(Sender: TObject);
var
  Msg: String;
  vonIP: in_addr; // für diesen Typ:  uses ..., WinSock;  ergänzen!
begin
  // Nachricht einlesen; in vonIP wird die Absender-IP zurückgegeben
  Msg := UdpSockUtil1.ReceiveText(vonIP);
  // Länge der Nachricht, die Nachricht und den Absender anzeigen
  ShowMessage(IntToStr(Length(Msg))+#13+Msg+#13+inet_ntoa(vonIP));
end;


History:
v1.00 vom 03.02.2006
- erste öffentliche Version
v1.01 vom 23.02.2010
- Anpassung an Unicode-Delphi-Versionen
v2.01 vom 13.03.2012
- Milestone-Release, Details in der PDF-Doku im Archiv

Kommentare zu der Komponente sind hier durchaus erwünscht.

cu
Narses


Narses - Di 21.02.06 15:57

Moin!

Das angekündigte LAN-Chat-Tutorial [http://www.delphi-library.de/topic_UDPProtokollChatTutorial+V100_56272.html] ist fertig. Viel Erfolg damit. :wink:

cu
Narses


Xantor - Di 07.03.06 16:14

Also - so wie ich es in einem ersten Test sehe, funktioniert das ganz ausgezeichnet. Übrigens, das Sync-Problem etc. taucht mit diesen Komponenten nicht auf. Jedes Packet wird gesendet und auch empfangen und das ganze ohne nennenswerte Latenz. Allerdings taucht nach rund 24000 Bytes ein Fehler auf - ich sende per Broadcast und da werden nicht alle Bytes von allen Rechnern abgeholt - oder liegt das am Sender?
Fehlermeldung: "Ein Socketvorgang konnte nicht ausgeführt werden, da dem SystemPufferspeicher fehlt oder eine Warteschlange voll war (10055), auf API'Bind' "

Hast du da auf anhieb eine Idee, was ich da falsch mache?


Basti2k - Di 07.03.06 16:55
Titel: Probleme mit falschem Host
Hallo, ich habe ein Problem. Stellt man mit der UdpSockUtil eine Verbindung zu einem Host her den es nicht gibt, kann man ohne neustarten des Programms keine Verbindung zu einem exsistierenden Host herstellen. Ich wüste auch nicht wie man das umgehen könnte. Ihr vieleicht?


thx


Xantor - Di 07.03.06 18:31

Ich glaub meinen Fehler hab ich gefunden: CloseInactiveSockets muß TRUE sein.


Narses - Di 21.03.06 02:26

Moin!

user profile iconXantor hat folgendes geschrieben:
Allerdings taucht nach rund 24000 Bytes ein Fehler auf - ich sende per Broadcast und da werden nicht alle Bytes von allen Rechnern abgeholt - oder liegt das am Sender?
Fehlermeldung: "Ein Socketvorgang konnte nicht ausgeführt werden, da dem SystemPufferspeicher fehlt oder eine Warteschlange voll war (10055), auf API'Bind' "

Hast du da auf anhieb eine Idee, was ich da falsch mache?

Ohne etwas mehr von deinem Quelltext zu sehen, kann ich nicht viel dazu sagen; deiner Beschreibung nach kann ich keinen "Fehler" erahnen... :gruebel: :wink:


user profile iconBasti2k hat folgendes geschrieben:
Hallo, ich habe ein Problem. Stellt man mit der UdpSockUtil eine Verbindung zu einem Host her den es nicht gibt, kann man ohne neustarten des Programms keine Verbindung zu einem exsistierenden Host herstellen.

Da es sich um UDP handelt (verbindungsloses Protokoll), kann man gar keine "Verbindungen" in diesem Sinne herstellen. Vielleicht solltest du dir mal das LAN-Chat-Tut ansehen. :wink: Zeig doch mal etwas von deinem Quelltext, dann kann ich möglicherweise auch mehr dazu sagen. Ein entsprechendes Verhalten konnte ich in meinen Tests nicht nachvollziehen.

cu
Narses


Xantor - Di 21.03.06 20:07

Wie gesagt: CloseInactiveSockets muß TRUE sein - dann funktioniert alles wunderbar


hui1991 - Mi 10.05.06 19:40

Bei mir fehlt die RTLConsts.
Woher bekomme ich sie?


Narses - Mi 10.05.06 22:57

Moin!

Welche Delphi-Version hast du denn? Sollte eigentlich dazugehören... ? :?

cu
Narses


hui1991 - Do 11.05.06 14:16

In Delphi 2005 kann ich so wie in der Anleitung das nicht installieren und in Delphi 5 fehlt RTLConsts. Liegt warscheinlich am Delphi 5.


Narses - Do 11.05.06 14:59

Moin!

Füg das in der TUdpSockUtil.pas ein, dann kannst du das uses RTLConsts; rausnehmen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
[...]
uses
  Windows, Messages, SysUtils, Classes, WinSock, SyncObjs;

resourcestring
  sWindowsSocketError = 'Windows-Socket-Fehler: %s (%d), auf API ''%s''';
  sCannotCreateSocket = 'Es kann kein neuer Socket erzeugt werden';


const
  USU_WM_ASYNCSELECT = WM_USER +4711// eigene Fensternachricht
[...]

cu
Narses


hui1991 - Do 11.05.06 15:53

Ich hab nur noch fehler:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
[Warnung] UdpSockUtil.pas(230): Konstantenausdruck verletzt untere Grenzen
[Fehler] UdpSockUtil.pas(263): Undefinierter Bezeichner: 'DeallocateHWnd'
[Fehler] UdpSockUtil.pas(301): Undefinierter Bezeichner: 'AllocateHWnd'
[Fehler] UdpSockUtil.pas(301): Nicht genügend wirkliche Parameter
[Warnung] UdpSockUtil.pas(373): Konstantenausdruck verletzt untere Grenzen
[Warnung] UdpSockUtil.pas(387): Der Vergleich ergibt immer Falsch
[Warnung] UdpSockUtil.pas(406): Der Vergleich ergibt immer Falsch
[Warnung] UdpSockUtil.pas(496): Konstantenausdruck verletzt untere Grenzen
[Fataler Fehler] dclusr50.dpk(34): Verwendete Unit 'UdpSockUtil.pas' kann nicht compiliert werden


So ich hoffe das funktioniert bald, ich stehe grad im Stillstand...
...kann in moment nix anderes machen als die Komponete versuchen zu installieren.


Narses - Do 11.05.06 19:07

Moin!

Hm, ich hab unterhalb von D6 praktisch keine Erfahrung... :? Was spricht dagegen D7 zu nehmen? ;)


Quelltext
1:
2:
[Fehler] UdpSockUtil.pas(263): Undefinierter Bezeichner: 'DeallocateHWnd'
[Fehler] UdpSockUtil.pas(301): Undefinierter Bezeichner: 'AllocateHWnd'

Nimm halt mal das "Classes." weg und schau, ob der Compiler die Referenzen selbst auflösen kann.

cu
Narses


hui1991 - Do 11.05.06 21:03

Keine Lust mehr ich besorge mir D7
D5 ist denke ich zu alt. Es wurde ja auch mit D7 getestet.
Es hat dort geklappt.
Weil so komm ich mit meinem Programm net weiter. :cry:


Narses - Do 22.06.06 15:22

Moin!

Da die Frage aufkam: "Wie kann ich die Portnummer des Absenders ermitteln?", hier der Ansatz, um diese Information abzugreifen.

Im Quelltext der Komponente steht diese Information beim Lesen aus dem WSA-Puffer bereit, allerdings wird die Portnummer nicht nach Aussen weitergegeben (da die Information sehr selten sinnvoll verwendbar ist):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
// vom Empfänger-Socket lesen; Puffer-Variante  
function TUdpSockUtil.ReceiveBuf(var Buf; BufSize: Integer; var RemoteAddr: in_addr; Flags: Integer = 0): Integer;  
  var  
    FromAddr: TSockAddrIn;  
    FromAddrLen: Integer;  
    ErrorCode: Integer;
    RemotePort: Integer;  
begin  
  FSocketLock.Enter;  
  try  
    Result := 0;  
    RemoteAddr.S_addr := -1;  
    if (FRecvSock <> INVALID_SOCKET) then begin  
      FromAddrLen := SizeOf(FromAddr);  
      ZeroMemory(@FromAddr,FromAddrLen);  
      Result := WinSock.RecvFrom(FRecvSock,Buf,BufSize,Flags,FromAddr,FromAddrLen);  
      if (Result = SOCKET_ERROR) then begin  
        ErrorCode := WSAGetLastError;  
        Result := 0;  
        if (ErrorCode <> WSAEWOULDBLOCK) then  
          if Assigned(FOnError) then begin  
            FOnError(Self,ErrorCode);  
            Abort;  
          end  
          else  
            raise EUSUError.CreateResFmt(@sWindowsSocketError,  
              [SysErrorMessage(ErrorCode), ErrorCode, 'RecvFrom']);  
      end  
      else begin
        RemoteAddr := FromAddr.sin_addr;  
        RemotePort := ntohs(FromAddr.sin_port); // Achtung! network-byteorder!
      end;
    end;  
  finally  
    FSocketLock.Leave;  
  end;  
end;

Mit den markierten Zeilen lässt sich die Portadresse ermitteln. Für die Übergabe nach Aussen stehen zwei Ansätze zur Verfügung:
a) Einen weiteren var-Parameter Port: Integer in der Funktionsdeklaration einfügen, oder
b) nicht in_addr, sondern TSockAddrIn als Remote-var-Parameter nehmen, dann wird alles zurückgeliefert.

cu
Narses


oern - Sa 24.06.06 14:15

Erstmal muss ich loswerden das das die beste netzwerk komponente ist mit der ich je gearbeitet habe :)

Zur zeit versuche ich damit eine record zu versenden, dabei kommt aber die fehler meldung "Windows Socket Fehler: 10014 Ungültige zeiger adresse" diese meldung kann mich mir leider nicht erkären :(
Ich hoffe hier kann mir jemand helfen.

Hier meine Klasse:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
unit uglsn_engine;

interface

uses UdpSockUtil, SysUtils, Classes, IdIPWatch, Dialogs;

const
  GLSN_DEFAULTPORT = 42768;
  GLSN_STR = 0;
  GLSN_POS = 1;

type
  TGLS_IPString = string[18];   { size: 18    4*3+3 }
  TGLS_SString = string[20];    { size: 20          }
  TGLS_LString = string[255];   { size: 255         }
  TGLS_Point = packed record    { size: 24    3*8   }
    X,
    Y,
    Z: Double;
  end;

type
  TGLS_NetSend = packed record { 394 }
    C: Integer;
    K: Integer;
    P: Integer;          { 12  }
    Name: TGLS_SString;  { 32  }
    case Integer of
      0:(
       M1,
       M2,
       M3,
       M4,
       M5: TGLS_SString;    { 142 }
       ML: TGLS_LString;    { 387 }
      );
      1:(
       Pos: TGLS_Point;     { 56  }
       Dir: TGLS_Point;     { 70  }
       Speed: Double;
       Power: Double;       { 86  }
      );
  end;

type
  TGLS_OnReceiveEvent = procedure(r: TGLS_NetSend;ip: stringof object;
  TGLS_Network = class (TUdpSockUtil)
  protected
    IP: TIdIPWatch;
    FOnRecieveRecord: TGLS_OnReceiveEvent;
    procedure Receive(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    procedure BroadcastRecord(r: TGLS_NetSend);
    procedure SendRecord(r: TGLS_NetSend);
  published
    property OnReceiveRecord: TGLS_OnReceiveEvent read FOnRecieveRecord write
                                                          FOnRecieveRecord;
  end;

implementation

uses WinSock;

{ TGLS_Network }

procedure TGLS_Network.BroadcastRecord(r: TGLS_NetSend);
var
  s: string;
begin
  Move(r, s, sizeof(TGLS_NetSend));
  Self.BroadcastText(s); // also auch hier
end;

constructor TGLS_Network.Create(AOwner: TComponent);
begin
  inherited;
  IP:= TIdIPWatch.Create(self);
  IP.HistoryEnabled:= false;
  Self.OnReceive:= Receive;
  Self.LocalPort:= GLSN_DEFAULTPORT;
  Self.RemotePort:= GLSN_DEFAULTPORT;
  Self.Listen:=true;
end;

procedure TGLS_Network.Receive(Sender: TObject);
var
  Len: Integer;
  Msg: String;
  vonIP: in_addr;
  r: TGLS_NetSend;
begin
  // wieviel ist angekommen?
  Len := Self.ReceiveLength;
  if (Len > 0then begin // wenn auch was da ist...

    // Nachricht einlesen; in vonIP wird die Absender-IP zurückgegeben
    Msg := Self.ReceiveText(vonIP);
    if inet_ntoa(vonIP)<>IP.LocalIP then
    begin
      if Len=sizeof(TGLS_NetSend) then begin
        if Assigned(FOnRecieveRecord) then begin
          Move(msg, r, sizeof(TGLS_NetSend));
          FOnRecieveRecord(r, inet_ntoa(vonIP));
        end;
      end;
    end;
  end;
end;

procedure TGLS_Network.SendRecord(r: TGLS_NetSend);
var
  s: string;
begin
  Move(r, s, sizeof(TGLS_NetSend));
  Self.SendText(s);
end;

end.

und der demo aufruf:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
unit uglsn_demo;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, uglsn_engine, StdCtrls;

type
  TGLSNWindow = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    n:TGLS_Network;
    procedure Receive(r: TGLS_NetSend; ip: string);
  end;

var
  GLSNWindow: TGLSNWindow;

implementation

uses WinSock;

{$R *.dfm}

procedure TGLSNWindow.FormCreate(Sender: TObject);
begin
  n:=TGLS_Network.Create(self);
  n.OnReceiveRecord:= Receive;
end;

procedure TGLSNWindow.Receive(r: TGLS_NetSend; ip: string);
begin
  case r.K of
    GLSN_STR:showmessage(r.ML);
    GLSN_POS:;
  end;
end;

procedure TGLSNWindow.Button1Click(Sender: TObject);
var
  r: TGLS_NetSend;
begin
  n.BroadcastRecord(r);// hier der fehler
end;


mfg, Björn

Edit hab das Problem gelöst, jetz klappt es mit records:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
interface

uses
  SysUtils, Classes, IdBaseComponent, IdComponent, IdIPWatch, UdpSockUtil,
  WinSock, Forms, Dialogs;

const
  ALL = '255.255.255.255';
  GLSN_DEFAULTPORT = 42768;
  GLSN_STR = 0;
  GLSN_POS = 1;

type
  TGLS_IPString = string[18];   { size: 18    4*3+3 }
  TGLS_SString = string[20];    { size: 20          }
  TGLS_LString = string[255];   { size: 255         }
  TGLS_Point = packed record    { size: 24    3*8   }
    X,
    Y,
    Z: Double;
  end;

type
  TGLS_NetSend = packed record { 394 }
    C: Integer;
    K: Integer;
    P: Integer;
    Name: TGLS_SString;
    case Integer of
      0:(
       M1,
       M2,
       M3,
       M4,
       M5: TGLS_SString;
       ML: TGLS_LString;
      );
      1:(
       Pos: TGLS_Point;
       Dir: TGLS_Point;
       Speed: Double;
       Power: Double;
      );
  end;

type
  TGLSN_Exception = Exception;
  TGLS_OnReceiveEvent = procedure(r: TGLS_NetSend;ip: stringof object;
  TGLSN_Engine = class(TDataModule)
    UdpSockUtil: TUdpSockUtil;
    IP: TIdIPWatch;
    procedure UdpSockUtilError(Sender: TObject; Error: Integer);
    procedure UdpSockUtilReceive(Sender: TObject);
    procedure DataModuleCreate(Sender: TObject);
  protected
    FOnRecieveRecord: TGLS_OnReceiveEvent;
  public
    { Public-Deklarationen }
    Eceptions: boolean;
    procedure BroadcastRecord(r: TGLS_NetSend);
    procedure SendRecord(r: TGLS_NetSend; toip: string);
  published
    property OnReceiveRecord: TGLS_OnReceiveEvent read FOnRecieveRecord write
                                                          FOnRecieveRecord;
  end;

var
  GLSN_Engine: TGLSN_Engine;

implementation

{$R *.dfm}

procedure TGLSN_Engine.UdpSockUtilError(Sender: TObject; Error: Integer);
begin
  if Eceptions then
     TGLSN_Exception.Create('GLSN Socket Error: '+inttostr(Error));
end;

procedure TGLSN_Engine.UdpSockUtilReceive(Sender: TObject);
var
  Len: Integer;
  Msg: String;
  vonIP: in_addr;
  buffer: TGLS_NetSend;
begin
  // wieviel ist angekommen?
  Len := UdpSockUtil.ReceiveLength;
  if (Len > 0then begin // wenn auch was da ist...
    // Nachricht einlesen; in vonIP wird die Absender-IP zurückgegeben
    UdpSockUtil.ReceiveBuf(buffer, sizeof(buffer), vonIP);
    if inet_ntoa(vonIP)<>IP.LocalIP then
    begin
      if Assigned(FOnRecieveRecord) then begin
        FOnRecieveRecord(buffer, inet_ntoa(vonIP));
      end;
    end;
  end;
end;

procedure TGLSN_Engine.DataModuleCreate(Sender: TObject);
begin
  UdpSockUtil.Listen:=true;
end;

procedure TGLSN_Engine.BroadcastRecord(r: TGLS_NetSend);
var
  s: string;
begin
  s:=UdpSockUtil.RemoteHost;
  UdpSockUtil.RemoteHost:=ALL;
  UdpSockUtil.SendBuf(r, sizeof(r));
  UdpSockUtil.RemoteHost:=s;
end;

procedure TGLSN_Engine.SendRecord(r: TGLS_NetSend; toip: string);
var
  s: string;
begin
  s:=UdpSockUtil.RemoteHost;
  UdpSockUtil.RemoteHost:=toip;
  UdpSockUtil.SendBuf(r, sizeof(r));
  UdpSockUtil.RemoteHost:=s;
end;

end.


Narses - Sa 24.06.06 22:21

Moin!

user profile iconoern hat folgendes geschrieben:
Erstmal muss ich loswerden das das die beste netzwerk komponente ist mit der ich je gearbeitet habe :)

Danke. :D

user profile iconoern hat folgendes geschrieben:
Zur zeit versuche ich damit eine record zu versenden,

Ich möchte allerdings unter Hinweis auf diesen FAQ-Beitrag [http://www.delphi-library.de/topic_Probleme+beim+SendenEmpfangen+von+records++dyn+Objekten_60793.html] davon abraten, records zu versenden. :mahn: ;)

cu
Narses


oern - So 25.06.06 12:47

Zitat:
Ich möchte allerdings unter Hinweis auf diesen FAQ-Beitrag davon abraten, records zu versenden.

Gut, leider sind meine Netzwerk kennise dermaßen gering das ich mich jetzt freue das es klappt, und da ich keine records mit dyn typen verwende trit problem 1 nicht ein, an problem 2 kann ich jedoch nichts machen, erst mal jedenfalles, also werde ich bei meiner lösung bleiben solage sie funktioniert, und mein modul verändern sobald es nötigt wird, aber danke für den Hinweis.

mfg, Björn


freedy - Mo 26.06.06 09:54

Auch wir nutzen die Komponente. Uns gefällt vor allem, dass sie so klein und schlank ist.

Das Versenden von Records macht uns keine Probleme. Durch einen fest definierten Header, den wir jedem UDP-Paket vorwegstellen, umgehen wir das Problem, irgendwo mal Datensalat zu bekommen.

Inzwischen habe ich eine weitere Klasse abgeleitet, die sogar einen Handshake ermöglicht und Daten, die auf mehrere Pakete aufgeteilt wurden, wieder zusammensetzt. Warum das Ganze wo es doch TCP gibt? :-) Fragt meinen Chef. Ich mache schließlich auch nur, was mir gesagt wird. ;-)


Narses - Mo 26.06.06 11:48

Moin!

user profile iconfreedy hat folgendes geschrieben:
Auch wir nutzen die Komponente. Uns gefällt vor allem, dass sie so klein und schlank ist.

Nochmal Danke. :D

user profile iconfreedy hat folgendes geschrieben:
Das Versenden von Records macht uns keine Probleme. Durch einen fest definierten Header, den wir jedem UDP-Paket vorwegstellen, umgehen wir das Problem, irgendwo mal Datensalat zu bekommen.

Das Problem liegt leider genau an dieser Stelle: wer noch nie auf Grund von unvorhersehbaren Anforderungen seine "festen Definitionen" wieder gelöst hat, der "werfe das erste Record" (mal frei philosophiert ;)).

cu
Narses


oern - Fr 30.06.06 21:37

Hi,

Ich habe noch eine Frage zur Komponente, ich habe oben im Quelltext gelesen das die maximale Paketgröße 512 byte ist. Was passiert nun wenn ich jetzt ein sagen wir 393 Byte großes Paket sende. Werden dann nur 393 Byte gesendet oder 512 Byte ?

mfg, Björn


Narses - Fr 30.06.06 23:28

Moin!

user profile iconoern hat folgendes geschrieben:
Werden dann nur 393 Byte gesendet

Yip, plus UDP-Protokoll-Overhead von ein paar Bytes.

cu
Narses


GlobalImpact - Do 27.07.06 17:32

Hi,
bin grad auf den Beitrag gestoßen.
Habs ordnungsgemäß installiert, nur bei mir wird ein Fehler angezeigt:

Undefinierter Bezeichner "in_addr"
Und zwar jetz konkret, wenn ich das UPDRecieve Erigniss benutze.


Edit:

Hab Delphi 2005 PE

Danke für die Antwort

mfg GlobalImpact


Fighter#1 - Do 27.07.06 17:36

Winsock muss bei uses eingebungen werden


PlugnPray - So 30.07.06 10:51

Kann mir mal einer bitte sagen, wie ich es unter Delphi 2005 zum Laufen kriege?
Die Installation bezieht sich ja nur auf Delphi 7, aber in 05 nimmt es die Dateien nicht an.
Danke.


Fighter#1 - So 30.07.06 11:12

Einfach in den Delphi 2005 Hauptordner (nicht Bin) packen, oben einbinden dann in Private oder Public einbinden, hier ein Bsp:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
uses ...,UDPSockUtil,Winsock;

type

...
procedure UdpSockUtil1Receive(Sender: TObject);

...
private
  udp:TUDPSockUtil;

...


udp:=TUDpSockutil.Create(self);
udp.Name:='Udp1';
udp.LocalPort:=2555;
udp.Listen:=True;
udp.OnReceive:=Form1.UdpSockUtil1Receive;

...

procedure TForm1.UdpSockUtil1Receive(Sender: TObject);
var
  Msg: String;
  vonIP: in_addr;
begin
  
Msg := Udp.ReceiveText(vonIP);
ShowMessage(Msg);
  end;


PlugnPray - So 30.07.06 11:34

Danke schön, das ging fix :)


Fighter#1 - So 30.07.06 18:45

Keiner wartet gern ...


redjustice - Sa 19.08.06 12:59

Hey!

Kurz eine Frage, ich checke das UDP Protokoll noch nicht so ganz zu 100%...

Kann man auch Broadcast's ins Internet senden?
Oder ist sowas nur im lokalen Netzwerk möglich?

Thx!

MfG red


Fighter#1 - Sa 19.08.06 14:15

Geht auch im Internet, aber nur bei einem Bestimmten Address bereich in dem du bist.
Ich glaub die Internetprovider ham so ihre eigenen Addressbereiche ...


Narses - So 20.08.06 00:05

Moin!

user profile iconredjustice hat folgendes geschrieben:
Kann man auch Broadcast's ins Internet senden?
Oder ist sowas nur im lokalen Netzwerk möglich?

Faktisch geht das nur im LAN, da die Provider UDP-Broadcasts fast immer filtern. (Macht auch durchaus Sinn, da sonst die Netzbelastung unnütz stark ansteigt...)

Allerdings kannst du problemlos UDP-Pakete über das Internet an bestimmte IP-Adressen versenden.

cu
Narses


freedy - Fr 25.08.06 14:55

Hallo Narses!
Ich bin heute auf folgendes Problem gestoßen. Meine Delphi Entwicklungsumgebung hat eine Verbindung zu dem PC aufgenommen, der mir alle halbe Sekunde ein UDP-Paket schickt. Jetzt hat BDS2006 auch den Port belegt, der zum Abhören gedacht war. Finde ich total merkwürdig.

Seitdem läuft meine Anwendung jedenfalls nicht mehr unter der IDE. Dabei bin ich darauf gestoßen, dass noch keine Funktion gibt, die prüft, ob der Port überhaupt frei ist. Kann man (du ;-) ) das noch einbauen?




PS: Sollte jemand wissen, wie ich die Verbindung, die BDS2006 aufgebaut hat, wieder kappen kann, bitte ich um Nachricht!!!


Narses - Fr 25.08.06 16:04

Moin!

user profile iconfreedy hat folgendes geschrieben:
Meine Delphi Entwicklungsumgebung hat eine Verbindung zu dem PC aufgenommen

:shock: Warum sollte denn eine IDE(!) selbstständig(!) eine UDP-Verbindung aufbauen... :nixweiss: :gruebel: :?

user profile iconfreedy hat folgendes geschrieben:
Jetzt hat BDS2006 auch den Port belegt, der zum Abhören gedacht war. Finde ich total merkwürdig.

Allerdings, da stimmt doch was nicht... :|

user profile iconfreedy hat folgendes geschrieben:
noch keine Funktion gibt, die prüft, ob der Port überhaupt frei ist. Kann man (du ;-) ) das noch einbauen?

Ist doch schon drin. Die Methode .Listen erzeugt dann einen Fehler, den du entsprechend behandeln kannst (WSA-Code weiß ich gerade nicht, lass ihn dir doch einfach im OnError ausgeben ;)).

cu
Narses


freedy - Fr 25.08.06 18:13

Stimmt. Auf die Fehlerbehandlung bin ich inzwischen auch schon gekommen.

Aber die IDE macht mir wirklich Sorgen. Mit einem Mal meldete die Firewall, dass besagter Rechner eine Verbindung mit BDS haben will. Gut, habe ich blockiert. Dann ging gar nichts mehr.

"netstat -ano" sagt mir, dass der Port jetzt immer von Delphi belegt ist. Warum? Keine Ahnung. Ich erkläre mir das damit, dass das BDS ja auch Nachrichten von Borland empfängt. Vielleicht lernt es ja und wenn Nachrichten zufällig auf einem Port ankommen, wird der für zukünftige auch reserviert.

Starte ich meine Anwendung zuerst und dann das BDS semmelt das total ab mit Pointerverletzungen etc. Es lässt sich dann auch nicht mehr beenden. Tja. Montag schauen wir dann mal weiter.

Ein schönes Wochenende.


Force - Fr 15.09.06 20:22

hey, ich hab ein kleines Problem mit dem UDPSockUtil:

Ich habe einen Procedure, die aufgerufen wird, wenn man einen Button klickt oder ein timer einsetzt. Die Procedure soll an alle Server in einer Liste neun Bytes senden, wenn der Server online ist, sollte eine 166-Byte-Antwort kommen. Allerdings funktioniert die Procedure nur beim ersten Aufruf. Ab dem zweiten Aufruf sendet UDPSOckutil (so weit ich weiß) alle Anfragen nur an einen Server und empfängt nichts mehr (auch wenn die Anfragen an den richtigen Server gesendet wurden).


Hier ist der Quelltext, wär super, wenn jemand mir helfen könnte....


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
procedure TForm1.Button5Click(Sender: TObject);
var i,j:integer;
byte1,byte2,byte3:byte;
begin
button5.Enabled:=false;
memo1.Enabled:=false;
button5.Caption:='Removing empty Data';
for i:=0 to memo1.Lines.Count do begin
 memo1.Lines[i]:=stringreplace(memo1.Lines[i],' ','',[rfReplaceAll]);
 memo1.Lines[i]:=stringreplace(memo1.Lines[i],#13+#10,'',[rfReplaceAll]);
 if memo1.Lines.ValueFromIndex[i]='' then memo1.Lines.Delete(i);end;
button5.Caption:='Removing dublicates';
for i:=0 to memo1.Lines.Count do begin
for j:=0 to memo1.Lines.Count do if (memo1.Lines[i]=memo1.Lines[j]) AND (i<>j) then memo1.Lines.Delete(j); 
end;
button5.Caption:='Scanning';
byte1:=00;
byte2:=02;
byte3:=32;
progressbar1.Max:=memo1.Lines.Count;
for i:=0 to memo1.Lines.Count do begin
udpsockutil1.RemoteHost:=stringreplace(memo1.Lines[i],#13+#10,'',[rfReplaceAll]);
if udpsockutil1.RemoteHost='255.255.255.255' then memo1.Lines.Delete(i) else
udpsockutil1.SendText(chr(byte2)+chr(byte1)+chr(byte1)+chr(byte3)+chr(byte1)+chr(byte1)+chr(byte1)+chr(byte1)+chr(byte1));
progressbar1.Position:=i;
end;
button5.Caption:='Scan for Games';
button5.Enabled:=true;
memo1.Enabled:=true;
progressbar1.Position:=0;
end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
procedure TForm1.UdpSockUtil1Receive(Sender: TObject);
  var
  Len: Integer;
  servername,gamemode,levelname,s,ip: String;
  vonIP: in_addr;
  i,currentlyplaying,maxplayers:integer;
  newserver:TTreenode;
begin
  Len := UdpSockUtil1.ReceiveLength;
  if Len =166 then begin
    servername:='';
    gamemode:='';
    levelname:='';
    s:=udpSockUtil1.ReceiveText(vonIP);
    ip:=string(inet_ntoa(vonIP));
    ips.Add(ip);
    for I:=62 to 93 do servername:=servername+s[i];
    for I:=94 to 125 do gamemode:=gamemode+s[i];
    for I:=126 to 157 do levelname:=levelname+s[i];
    currentlyplaying:=ord(s[158]);
    maxplayers:=ord(s[162]);
    newserver:=treeview1.Items.add(nil,ip+': '+servername);
    treeview1.items.AddChild(newserver,'Gamemode: '+gamemode);
    treeview1.items.AddChild(newserver,'Level: '+levelname);
    treeview1.items.AddChild(newserver,'Players: '+inttostr(currentlyplaying)+'/'+inttostr(maxplayers));
    ping1.Hostname:=ip;
    ping1.ResetStatistics;
    ping1.action;
    pinging:=true;
    while pinging do application.ProcessMessages;
    treeview1.items.AddChild(newserver,'Ping: '+inttostr(lastping)+'ms');
  end;



Config von UDPSockutil1:

Broadcast=false
CloseInactive=false
LocalPort=51762
RemotePort=19400


Wie gesagt, wär echt klasse, wenn mir jemand helfen könnte...


PS: Das Scannen dauert mit dem zweiten Mal höchstens nur noch eine Sekunde, ab dem dritten Mal weniger als eine Sekunde, am Anfang dauerte es aber 2-3 Sekunden...


Narses - So 17.09.06 11:54

Moin!

user profile iconForce hat folgendes geschrieben:
Hier ist der Quelltext, wär super, wenn jemand mir helfen könnte....

Hm, wenn du deinen Quelltext brauchbar formatierst (Suche in: Delphi-Forum, Delphi-Library STYLEGUIDE) und aussagekräftige Kommentare einfügst, dann würde ich mir das mal ansehen; aber so ist mir das zu konfus. ;)

user profile iconForce hat folgendes geschrieben:
alle Server in einer Liste

Ein Beispiel für diese Liste wäre dann noch ganz nett. ;)

user profile iconForce hat folgendes geschrieben:
Ab dem zweiten Aufruf sendet UDPSOckutil (so weit ich weiß) alle Anfragen nur an einen Server und empfängt nichts mehr (auch wenn die Anfragen an den richtigen Server gesendet wurden).

Wie bist du auf diese Diagnose gekommen?

user profile iconForce hat folgendes geschrieben:
PS: Das Scannen dauert mit dem zweiten Mal höchstens nur noch eine Sekunde, ab dem dritten Mal weniger als eine Sekunde, am Anfang dauerte es aber 2-3 Sekunden...

Das ist nicht sehr ungewöhnlich und könnte damit zusammenhängen, dass die DNS-Auflösung jetzt aus dem Cache bedient wird, wenn du mit Hostnamen arbeitest. Näheres kann ich erst sagen, wenn du mehr aus dem Kontext deines Projekts vorstellst.

cu
Narses


Force - So 17.09.06 13:13

Zu dem Quelltext:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
procedure TForm1.Button5Click(Sender: TObject);
var i,j:integer;
byte1,byte2,byte3:byte;
begin
button5.Enabled:=false; //damit nich noch einmal draufgeklickt wird
memo1.Enabled:=false; //das ist die liste mit den IPs
button5.Caption:='Removing empty Data';
for i:=0 to memo1.Lines.Count do begin
 memo1.Lines[i]:=stringreplace(memo1.Lines[i],' ','',[rfReplaceAll]); //leere Lines löschen
 memo1.Lines[i]:=stringreplace(memo1.Lines[i],#13+#10,'',[rfReplaceAll]); //leere Lines löschen
 if memo1.Lines.ValueFromIndex[i]='' then memo1.Lines.Delete(i);end//leere Lines löschen
button5.Caption:='Removing dublicates';
for i:=0 to memo1.Lines.Count do begin
for j:=0 to memo1.Lines.Count do if (memo1.Lines[i]=memo1.Lines[j]) AND (i<>j) then memo1.Lines.Delete(j); //Dublikate löschen
end;
button5.Caption:='Scanning';
byte1:=00;
byte2:=02;
byte3:=32;
progressbar1.Max:=memo1.Lines.Count; //visuelle Anzeige zum Anzeigen des Fortschrittes
for i:=0 to memo1.Lines.Count do begin
udpsockutil1.RemoteHost:=stringreplace(memo1.Lines[i],#13+#10,'',[rfReplaceAll]); //den i-ten Host aus der Liste finden und einsetzen
if udpsockutil1.RemoteHost='255.255.255.255' then memo1.Lines.Delete(i) else //wenn der Host ungültig ist dann löschen
udpsockutil1.SendText(chr(byte2)+chr(byte1)+chr(byte1)+chr(byte3)+chr(byte1)+chr(byte1)+chr(byte1)+chr(byte1)+chr(byte1)); //9-Byte-Text zu dem Host senden
progressbar1.Position:=i;
end;
button5.Caption:='Scan for Games';
button5.Enabled:=true;
memo1.Enabled:=true;
progressbar1.Position:=0;
end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
procedure TForm1.UdpSockUtil1Receive(Sender: TObject);
  var
  Len: Integer;
  servername,gamemode,levelname,s,ip: String;
  vonIP: in_addr;
  i,currentlyplaying,maxplayers:integer;
  newserver:TTreenode;
begin
  Len := UdpSockUtil1.ReceiveLength;
  if Len =166 then begin //wenn die Antwort genau 166 Bytes lang ist
    servername:='';
    gamemode:='';
    levelname:='';
    s:=udpSockUtil1.ReceiveText(vonIP); //Antwort und IP in Variablen speichern
    ip:=string(inet_ntoa(vonIP));
    ips.Add(ip); //ips ist eine Stringlist, wo alle IPs dringespeichert sind
    for I:=62 to 93 do servername:=servername+s[i]; //Serverinfos rausfinden
    for I:=94 to 125 do gamemode:=gamemode+s[i];//Serverinfos rausfinden
    for I:=126 to 157 do levelname:=levelname+s[i];//Serverinfos rausfinden
    currentlyplaying:=ord(s[158]);//Serverinfos rausfinden
    maxplayers:=ord(s[162]);//Serverinfos rausfinden
    newserver:=treeview1.Items.add(nil,ip+': '+servername); //Serverinfos in ein Treeview stecken
    treeview1.items.AddChild(newserver,'Gamemode: '+gamemode); //Serverinfos in ein Treeview stecken
    treeview1.items.AddChild(newserver,'Level: '+levelname); //Serverinfos in ein Treeview stecken
    treeview1.items.AddChild(newserver,'Players: '+inttostr(currentlyplaying)+'/'+inttostr(maxplayers)); //Serverinfos in ein Treeview stecken
    ping1.Hostname:=ip; //Server anpingen (Habe ich allerdiungs in der neuen Version entfernt, da dadurch manchmal das Programm einfror
    ping1.ResetStatistics; //Server anpingen
    ping1.action; //Server anpingen
    pinging:=true; //Server anpingen
    while pinging do application.ProcessMessages; //Server anpingen
    treeview1.items.AddChild(newserver,'Ping: '+inttostr(lastping)+'ms'); //Ping hinzufügen
  end;



Beispiel für Liste (TMemo):

127.0.0.1
localhost
192.168.0.1
192.168.0.2

(hier stehen normalerweise IPs/DNS' für Server im Internet)

Zitat:
Wie bist du auf diese Diagnose gekommen?


Ich hab die gesendeten/empfangen Packete aufgezeichnet ;)


Narses - Mo 18.09.06 00:11

Moin!

Hm, nennst du das "formatierten Quelltext" und "aussagekräftige Kommentare"... ? :nixweiss: :roll:
Kannst du den Code nicht mal auf die definitiv relevanten Teile kürzen und exakt beschreiben, warum du das tust (was die Befehle machen, kann ich auch sehen...)? Danke. ;)

Was sind das für Server? Hast du die programmiert? Wer hat das Protokoll definiert? Beispiele?

Mir fällt auf Anhieb eigentlich nur folgendes am Code auf, für den Rest blicke ich einfach nicht brauchbar durch, ohne Stunden da rein zu investieren:
user profile iconForce hat folgendes geschrieben:

Delphi-Quelltext
1:
for i:=0 to memo1.Lines.Count-1 do begin                    

Du läufst mit dem Index permanent eins zu weit. ;)

user profile iconForce hat folgendes geschrieben:
Beispiel für Liste (TMemo):

Naja, dadrauf wäre ich dann auch gerade noch selbst gekommen... ;)

user profile iconForce hat folgendes geschrieben:
(hier stehen normalerweise IPs/DNS' für Server im Internet)

Und genau dafür hätte ich gerne mal ein Beispiel gesehen, um das mal selbst zu probieren. :D

Aber zumindest ist jetzt klar, warum das beim erst Aufruf länger dauert, als bei den folgenden; die Hostnamensauflösung kommt aus dem Cache. Gib mal zwischendurch "ipconfig /flushdns" ein, dann dauert das auch wieder länger. ;)

user profile iconForce hat folgendes geschrieben:
Zitat:
Wie bist du auf diese Diagnose gekommen?

Ich hab die gesendeten/empfangen Packete aufgezeichnet ;)

Womit? Und was genau hast du untersucht?

cu
Narses


Force - Di 19.09.06 16:48

user profile iconNarses hat folgendes geschrieben:

Was sind das für Server? Hast du die programmiert? Wer hat das Protokoll definiert? Beispiele?


Es handelt sich hierbei um Airfix Dogfigher Server (siehe auch: Hinweise zum ADF-Protokoll [http://www.jasdeepbansal.co.uk/Misc/Airfix_Dogfighter/]

user profile iconNarses hat folgendes geschrieben:

Mir fällt auf Anhieb eigentlich nur folgendes am Code auf, für den Rest blicke ich einfach nicht brauchbar durch, ohne Stunden da rein zu investieren:
Du läufst mit dem Index permanent eins zu weit. ;)


Stimmt, das hab ich übersehen :D

user profile iconNarses hat folgendes geschrieben:

Womit? Und was genau hast du untersucht?


Mit einem Packetdumper namens WPE Pro Alpha


Narses - Di 19.09.06 23:56

Moin!

Wenn du die Liste aus dem Archiv hast, dann würde ich sagen, da läuft einfach kein entsprechender Server oder der Antwortet nicht auf das MagicPaket.

Hier mein Testprojekt (mit spiegelndem Server, damit man das auch mal real testen kann ;)).

cu
Narses


Force - Mi 20.09.06 13:54

Ich hab zwar viele IPs auch aus dem Archiv, aber es ist auch möglich den Server lokal zu starten.

Trotzdem, wie schon gesagt, beim ersten Mal funktioniert es auch auch ohne Probleme, erst wenn die Procedure das zwetite Mal ausgeführt wird geht es nicht mehr...


Ich werd es mal mit deinen Projekten versuchen, vielen Dank dass du dir so viel Arbeit damit machst :D


Narses - Mi 20.09.06 14:27

Moin!

Ach ja, du brauchst auch noch meine Ping-Unit [http://www.delphi-forum.de/topic_ICMPEchoAPI+quotPingquot+WrapperUnit_53259.html] für mein Testprojekt. ;)

cu
Narses


testra - Di 26.09.06 10:08

kann man das ganze auch ohne formulare machen, ohne buttons usw.

Wie sähe der code aus, wenn ich nur datenempfang evtl. verschlüsselung vom server habe möchte und das vielleicht nur unter dem DOS-Fenster ausgeben möchte?


Narses - Di 26.09.06 10:31

Moin!

user profile icontestra hat folgendes geschrieben:
kann man das ganze auch ohne formulare machen, ohne buttons usw.

Nein, du brauchst das TApplication-Objekt für den MessageLoop, sonst kannst du die Nachrichten nicht verarbeiten.

cu
Narses


testra - Di 26.09.06 10:35

das gefällt mir nun gar nicht. :shock:

mein programm läuft ohne formulare und berechnet nur etwas, gibt das ergebnis in einer textdatei aus.

Als Sicherheit und Schutz, soll mein programm, damit es laufen soll, vom server einen text erhalten, das verschlüsselt ist, soll es vergleichen und dann somit das program starten.

aber ohne visuelle komponenten.

wie kann ich mit dem server kommunizieren, um diesen text zu erhalten.
die verschlüsselung wäre dann das nächste problem.


Narses - Di 26.09.06 11:32

Moin!

user profile icontestra hat folgendes geschrieben:
Als Sicherheit und Schutz, soll mein programm, damit es laufen soll, vom server einen text erhalten, das verschlüsselt ist, soll es vergleichen und dann somit das program starten.

Ich hoffe doch, dass dein Programm den Benutzer aber darüber informiert, dass es Daten mit deinem Server austauscht... :shock:

user profile icontestra hat folgendes geschrieben:
aber ohne visuelle komponenten.

Das ist ja auch OK, hab ich auch nicht gesagt. ;) Es geht nur um das TApplication-Objekt. ;) Und das auch nur für die Nachrichtenverarbeitung (asynchrone Benachrichtigung). Du kannst auch einen Thread abspalten und mit blocking-socket-calls direkt auf die WSA zugreifen und UDP-Transfers machen. :D

cu
Narses


testra - Di 26.09.06 11:35

ja moin auch!!

ist mir leider ein bischen zu hoch-deutsch!

ich bin da in socket-programmierung nämlich ein anfänger.

ein code-schnipsel wäre mir da lieber.. :roll:


Narses - Di 26.09.06 11:46

Moin!

user profile icontestra hat folgendes geschrieben:
ich bin da in socket-programmierung nämlich ein anfänger.

In diesem Fall würde ich dir dazu raten, eine Formular-Anwendung zu machen und einfach das Fenster zu verstecken. Code gibts dazu hier im Forum genug.

cu
Narses


testra - Di 26.09.06 14:32

ok, vielen dank!

werde ich versuchen.

trotzdem hätte es mich sehr interessiert, wie es ohne die gui funktioniert.. :wink:


Narses - Di 26.09.06 14:47

Moin!

user profile icontestra hat folgendes geschrieben:
trotzdem hätte es mich sehr interessiert, wie es ohne die gui funktioniert.. :wink:

Ich habe dir bereits einen Vorschlag gemacht; dein Kommentar:
user profile icontestra hat folgendes geschrieben:
ist mir leider ein bischen zu hoch-deutsch!

:D

cu
Narses


testra - Mi 27.09.06 13:31

man findet leider viel zu wenig stoff zu socket programmierung, und wenn dann nur mit der gui.

wie soll ich überhaupt das formular verstecken, die ganzen routinen nützen mir doch nix, weil
vieles auf onklick ereignisse aufgebaut ist. ich hätte die server-verbindung + datenempfang
ohne klicks; wie der aublauf in einer datei gesammelt werden soll ist mir noch völlig unklar.


Narses - Mi 27.09.06 14:34

Moin!

user profile icontestra hat folgendes geschrieben:
wie der aublauf in einer datei gesammelt werden soll ist mir noch völlig unklar.

Ich will dir ja nicht zu nahe treten, aber vielleicht solltest du dich erstmal mit den "wichtigen" Problemen beschäftigen und dann erst dafür sorgen, dass das ganze ohne GUI läuft. Wenn du das schon mit einer GUI nicht hinkriegst, dann wird das ohne GUI schonmal gar nix, oder? :D

user profile icontestra hat folgendes geschrieben:
wie soll ich überhaupt das formular verstecken, die ganzen routinen nützen mir doch nix, weil vieles auf onklick ereignisse aufgebaut ist. ich hätte die server-verbindung + datenempfang ohne klicks;

Grundsätzlich: wer hat denn gesagt, dass für den Datenempfang ein OnClick-Ereignis nötig ist? :gruebel: Dem ist nicht so! ;)

Vorschlag: mach deine Anwendung doch erstmal mit einem normalen Fenster und einem Button, in dessen Handler du alles "Nötige" zum Senden abwickelst.

Wenn das einwandfrei klappt, dann verschiebst du die Aktionen aus dem ButtonHandler in das FormCreate und setzt da auch als erstes den Code zum Fenster-verstecken ein.

Im Receive-Event behandelst du dann, was vom Server zurück kommt und beendest ggfs. die Anwendung. Und dabei wird kein Fenster je des Benutzers Auge streifen... ;)

cu
Narses


raziel - Mi 27.09.06 22:50

Die Frage von user profile icontestra habe ich hierhin [http://www.delphi-forum.de/topic_Zugriffsverletzung+bei+Sockets_64946.html] abgetrennt.

Gruß,
raziel


wurzel - Fr 15.12.06 10:19
Titel: Help
Ich kann die Komponente nicht in mein Delphi 2006 reinklöppeln, die will einfach net. Den Punkt "Komponente installieren" gibts bei mir nicht, nur "Neue VCl-Komponente", "Packages installieren" und "Komponente importieren". So, nun denke ich mir, dass ich mal "Neue VCL-Komponente" anklicke, da kann ich aber keine neuen Komponenten hinzufügen. Bitte, helft mir ^^


wulfskin - Fr 15.12.06 11:38
Titel: Re: Help
user profile iconwurzel hat folgendes geschrieben:
Ich kann die Komponente nicht in mein Delphi 2006 reinklöppeln, die will einfach net. Den Punkt "Komponente installieren" gibts bei mir nicht, nur "Neue VCl-Komponente", "Packages installieren" und "Komponente importieren". So, nun denke ich mir, dass ich mal "Neue VCL-Komponente" anklicke, da kann ich aber keine neuen Komponenten hinzufügen. Bitte, helft mir ^^
Hallo,

erstell ein Package oder, weil du wahrscheinlich nicht weißt wie das geht, lass es Narses für dich machen! ;) Das gehört sowieso eigentlich immer dazu!

Gruß Hape!


wurzel - Fr 15.12.06 11:59

Joa, wenn es einer machen könnte, wäre es cool, oder du sagst mir schnell, wie ich ein Package mache, oder wo ich ein Tut finde


wurzel - Fr 15.12.06 12:07

Muhaha, ich habe Feuer gemacht ^^. Ich habe es ehr wohl alleine hingekriegt, einfach "Datei - Neu - Weitere - Package". Dann mit Rechtsklick auf das Package im Projektmanager, "Hinzufügen" auswählen und die *.pas raussuchen. Und dann nur noch installieren. Fertig ^^.


hui1991 - Sa 23.12.06 12:03

Hi,

so nach langer Zeit versuche ich es mit D7 nochmal. Die komponente wird irgendwie in Internet eingefügt.
Ich hoffe das jetzt die anderen das besser installieren können.
Hätte wurzel nicht gesagt wie, dann hätte ich es aufgegeben.
Da ich schon vergessen hab wie man das installiert ^^
Jetzt wird erstmal getestet ^^

MfG
hui1991

Edit:// Okay es installiert doch nicht :(


xZise - Di 28.08.07 08:18

Entschuldigung, dass ich Thread so ausgrabe, aber ich benötige die Unit für Delphi 5, da ich hier nichts anderes habe.

Nun. Die Ressourcestrings konnte ich einbauen, und das verletzten der Grenzen auch (durch casten), aber jetzt meint er:

Quelltext
1:
2:
3:
4:
5:
6:
7:
[Fehler] UdpSockUtil.pas(262): Undefinierter Bezeichner: 'DeallocateHWnd'
[Fehler] UdpSockUtil.pas(300): Undefinierter Bezeichner: 'AllocateHWnd'
[Fehler] UdpSockUtil.pas(300): Nicht genügend wirkliche Parameter
[Warnung] UdpSockUtil.pas(372): Konstantenausdruck verletzt untere Grenzen
[Warnung] UdpSockUtil.pas(386): Der Vergleich ergibt immer Falsch
[Warnung] UdpSockUtil.pas(405): Der Vergleich ergibt immer Falsch
[Warnung] UdpSockUtil.pas(495): Konstantenausdruck verletzt untere Grenzen


Crosspost mit der DP [http://www.delphipraxis.net/post768782.html#768782]


Narses - Di 28.08.07 10:09

Moin!

user profile iconxZise hat folgendes geschrieben:
ich benötige die Unit für Delphi 5, da ich hier nichts anderes habe.

An dieser Stelle waren wir leider schonmal (s.o.). Wenn du allerdings nur D5 hast, ist hier Ende, weil ich kein D5 habe und dir leider nicht weiterhelfen kann. :nixweiss: :(

cu
Narses


barrais - Di 02.10.07 10:53

du hast gestern gemeint, wenn man die Unit-Referenzen anpasst, lässt sich TUdpSockUtil mit D5 compilieren.
Weißt du vielleicht welche das sind? und wie man die anpassen kann?


Narses - Di 02.10.07 12:07

Moin!

phlux in der DP hat folgendes geschrieben:
ein bisschen google hätte geholfen, für
Zitat:
[Fehler] UdpSockUtil.pas(262): Undefinierter Bezeichner: 'DeallocateHWnd'
[Fehler] UdpSockUtil.pas(300): Undefinierter Bezeichner: 'AllocateHWnd'

musst du die unit classes einbinden ab delphi 6, delphi5 und kleiner die unit forms.
der letzte fehler hängt damit zusammen, dass du zu wenige parameter übergibst

Also einfach mal:

Delphi-Quelltext
1:
2:
uses
   ..., Forms;

ergänzen und sehen, was der Compiler sagt. :nixweiss:

Ich habe leider kein D5, deshalb kann ich dir nicht wirklich helfen... :|

cu
Narses


barrais - Di 02.10.07 13:30

Danke Narses, es hat funktioniert!

Keine Fehler mehr, nur Warnungen:

[Warnung] UdpSockUtil.pas(230): Konstantenausdruck verletzt untere Grenzen
bezieht sich auf folgende Zeile: (FRemoteAddr.S_addr := INADDR_BROADCAST;)

[Warnung] UdpSockUtil.pas(387): Der Vergleich ergibt immer Falsch
bezieht sich auf folgende Zeile: if (Value.S_addr = INADDR_BROADCAST) then

[Warnung] UdpSockUtil.pas(387): Vorzeichenbehaftete und -lose Typen werden verglichen - beide Operanden werden erweitert
bezieht sich auf folgende Zeile: if (Value.S_addr = INADDR_BROADCAST) then


was meinst du, ist das was ernsthaftes, oder kann ich die ignorieren?


Narses - Di 02.10.07 13:57

Moin!

Mach das mal so:

Delphi-Quelltext
1:
2:
3:
4:
5:
FRemoteAddr.S_addr := Integer(INADDR_BROADCAST);

if (Value.S_addr = Integer(INADDR_BROADCAST)then

if (Value.S_addr = Integer(INADDR_BROADCAST)then

Was sagt der Compiler jetzt?

cu
Narses


barrais - Di 02.10.07 14:38

Danke schön!
der Compiler mekert nicht mehr!
ich versuche jetzt ein binäres Protokoll mit TUdpSockUtil zu schreiben.
Könntest du mir vieleicht Tipps geben?(ich weiß, ich frage zuviel, sorry..)


Narses - Di 02.10.07 15:14

Moin!

user profile iconbarrais hat folgendes geschrieben:
Danke schön!
der Compiler mekert nicht mehr!

Fein; bitte. ;) Schickst du mir mal die pas-Datei der Unit per PN zu, damit ich die Änderungen für D5 in das Projekt einpflegen kann?

user profile iconbarrais hat folgendes geschrieben:
ich versuche jetzt ein binäres Protokoll mit TUdpSockUtil zu schreiben.
Könntest du mir vieleicht Tipps geben?(ich weiß, ich frage zuviel, sorry..)

Grundsätzlich, ja. Aber da ich keine Ahnung habe, was das Ziel dieser Aktion sein soll und welche Daten verarbeitet werden, weiß ich nicht, wie. :nixweiss:

cu
Narses


barrais - Di 02.10.07 15:48

Hi,

die .pas-Datei habe ich dir per PN geschickt.

Was mein Projekt angeht:

ich habe vor, ein Anwendungsprogramm mit Delphi zu schreiben, das ein Mikrocontroller steuert; und zwar das Programm schickt per Ethernet UDP-Pakete zu dem Mikrocontroller, die Pakete enthalten Kommandos ( Start, Stop, Capture,...), der Mikrocontroller(werde ich noch mit C programmieren) reagiert dem Kommando entsprechend(z.B. start: Messung starten, stop: Messung stoppen, capture: die Messdaten zum PC schicken).Es geht um CAN-Bus Daten (also Binäre daten), die das Anwendungsprogramm dann speichert und binär(halt so wie sie sind!) darstellen muss.

Ich hoffe, du hast jetzt einen Überblick über das projekt.

ich bin für jeden Tipp Dankbar!


Narses - Mi 03.10.07 00:40

Moin!

user profile iconbarrais hat folgendes geschrieben:
ich habe vor, ein Anwendungsprogramm mit Delphi zu schreiben, das ein Mikrocontroller steuert; und zwar das Programm schickt per Ethernet UDP-Pakete zu dem Mikrocontroller, die Pakete enthalten Kommandos ( Start, Stop, Capture,...),

Damit entfernen wir uns vom TUdpSockUtil (der hat als Socket-Wrapper ja mit dem Protokoll nix zu tun!). Deshalb möchte ich dich bitten, bei weiteren Fragen zur Protokoll-Entwicklung einen passenden Thread in der Sparte Internet / Netzwerk [http://www.delphi-forum.de/forum_Internet++Netzwerk_7.html] aufzumachen. Hier geht es ja konkret um die Komponente. Danke. ;)

//EDIT: Hier geht´s weiter [http://www.delphi-forum.de/viewtopic.php?t=76976] mit dem Projekt von user profile iconbarrais.

cu
Narses


barrais - Do 04.10.07 09:34

Danke für Deine Tipps


Ernst Budde - Di 30.10.07 14:21
Titel: TUDPSockUtil für Delphi5
Ich habe jetzt TUDPSockUtil für Delphi 5 (Windows 2000) installiert. Dazu musste ich RTLConsts.pas hinzufügen und die beiden Classes. .. Aufrufe durch Forms. .. ersetzen.
Kompilieren geht jetzt gut. Aber der erste Test scheitert:
Ich starte z.B. UdpLanChat.exe aus dem Tutorial zweimal auf meinem Rechner. Der 'Senden' Button ist dann zunächst bei beiden grau.
Bei einer der beiden Anwendungen kann ich jetzt 'Online' drücken: Der Senden Button wird dann aktiv. Sobald ich aber auf der anderen Anwendung 'Online' drücke, bekomme ich ERROR 10048 und der 'Senden' button bleibt grau. Es kann doch nicht sein, dass man nur sich selbst etwas senden kann!
Ich habe den Code der Komponente noch nicht gelesen (und möchte das eigentlich auch nicht), aber eine Frage: Wird vielleicht beim Drücken des 'Online' Button versucht, einen SERVER einzurichten? Das sollte ja bei UDP nicht nötig sein, würde aber den Fehler erklären, denn auf einem Rechner dürfen nicht zwei Server mit gleicher Portnummer arbeiten.

Ernst


Narses - Di 30.10.07 15:38
Titel: Re: TUDPSockUtil für Delphi5
Moin!

user profile iconErnst Budde hat folgendes geschrieben:
eine Frage: Wird vielleicht beim Drücken des 'Online' Button versucht, einen SERVER einzurichten?
Genau so ist es. ;)

user profile iconErnst Budde hat folgendes geschrieben:
Das sollte ja bei UDP nicht nötig sein,
Aha, und wie willst du dann Daten empfangen? :gruebel:

user profile iconErnst Budde hat folgendes geschrieben:
würde aber den Fehler erklären, denn auf einem Rechner dürfen nicht zwei Server mit gleicher Portnummer arbeiten.
AFAIR steht genau zu deinem "Problem" ein entsprechender Hinweis im Chat-Tut. ;) Man kann das Demo-Programm jeweils nur einmal auf dem PC online schalten.

cu
Narses


GrubenPete - Mo 17.03.08 01:43

Hi, ich benutze TUdpSockUtil um im LAN alle aktiven Server für mein Spiel zu finden.
Gleichzeitig läuft auch ein TCPServer (von den Indys).
UDPSockUtil.Listen hab ich auf true und der TCPServer is auch aktiv.
Sende ich nun ne Broadcast erhalte ich ganz normal Antworten von allen Servern, will ich mich aber dann mit einem von denen per TCP Verbinden, kommt ein 'Connection refused'.
Hab dann mal testweise vorm verbinden mit TCP über die UDP-Komponente an meinen RemoteHost nen Befehl gesendet, der Listen auf false setzt und siehe da, ich kann mich via TCP auf den Host verbinden.
Nun meine Frage.^^ Lässt sich das irgendwie unterbinden, dass ich den UDP-'Listener' ausschalten muss, um mich mit dem TCPServer zu vebinden ?

Sascha


Narses - Mo 17.03.08 02:00

Moin!

user profile iconGrubenPete hat folgendes geschrieben:
Hab dann mal testweise vorm verbinden mit TCP über die UDP-Komponente an meinen RemoteHost nen Befehl gesendet, der Listen auf false setzt und siehe da, ich kann mich via TCP auf den Host verbinden.
Nun meine Frage.^^ Lässt sich das irgendwie unterbinden, dass ich den UDP-'Listener' ausschalten muss, um mich mit dem TCPServer zu vebinden ?
TCP und UDP haben je einen eigenen Port-Adressraum, ausserdem wird ja für den TCP- und den UDP-Listener je ein eigenes Binding erstellt. Ich kann mir nicht vorstellen, dass der TUdpSockUtil den IdTCPServer daran hindern sollte, eine Verbindung anzunehmen. :nixweiss:

Kurz: ich kann dir nicht sagen, woran es in deinem Projekt liegt, aber deinen "Verdacht" halte ich für sehr unwahrscheinlich. :gruebel: (ich habe selbst Projekte in dieser Konstellation laufen, da gibt es keine Probleme)

cu
Narses


GrubenPete - Mo 17.03.08 13:17

Hmm, hatte ich mir ja eigentl. auch gedacht, aber hab trotzdem mal verschiedene Ports ausprobiert. Ohne Erfolg.
Aus irgendeinem Grund müssen sich die beiden Server aber irgendwie in die Quere kommen, ich weiß aber nich warum.
Wenn ich wieder ab meinem PC bin poste ich mal den relevanten Quellcode sowie die einzelnen Einstellungen... Vielleicht findet sich ja dann irgendwo ein Fehler^^

Sascha


GrubenPete - Mo 17.03.08 16:54

Joa, das sind die meiner Meinung nach relevanten Zeilen..


Unit1
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
[...]

procedure TForm1.FormCreate(Sender: TObject);
begin
  myUDP := TUDPSockUtil.Create(self);
  myUDP.RemotePort := UDP_PORT; //12345
  myUDP.LocalPort := UDP_PORT;
  myUDP.OnReceive := myUDPReceive;
  myUDP.OnError := myUDPError;
  myUDP.Listen := true;

  myTCPClient.BoundIP := myIPWatch.LocalIP;
  myTCPClient.BoundPort := TCP_CLIENT_PORT; //12346
  
  myTCPServer.DefaultPort := TCP_SERVER_PORT; //12347
  myTCPServer.Active := true;

  [...]

end;

procedure TForm1.Button2Click(Sender: TObject); //Broadcast senden
begin
  Log.Lines.Add(TimeToStr(now) +': Sending Broadcast Question');
  myUDP.BroadcastText(APP_ID+#13// Kennung
                      Syntax[cmdBroadAsk].Text+#13); // Befehl
                      //Input.Text+#13); // Argument

  ServerList.SetFocus;
end;

procedure TForm1.ServerListClick(Sender: TObject);
var
  server: string;
begin
  if ( ServerList.Row > 0 ) and ( ServerList.Row < ServerList.RowCount )
          and not ( ServerList.Cells[1,ServerList.Row] = '' )
          then
    begin
      server := copy(ServerList.Cells[1,ServerList.Row],1,pos(' (',ServerList.Cells[1,ServerList.Row]));
      Log.Lines.Add('Trying to connect to ' + server);
      myUDP.RemoteHost := server;
      myUDP.SendText(APP_ID+#13// Kennung
                      Syntax[cmdStop].Text+#13); // Der Befehl um myUDP.Listen auf false zu setzen
      myTCPClient.Host := server;
      myTCPClient.Port := TCP_SERVER_PORT; //12347
      myTcpClient.Connect(); //Ohne das vorherige stoppen von myUDP.Listen kommt hier ein 'Connection refused'
    end;
end;

[...]


Narses - Mo 17.03.08 17:26

Moin!

Der Codeschnipsel ist zu kurz, da kann ich nix erkennen. Interessanter ist auch eher die Empfänger-Seite, würde ich sagen. Vor allem ist der IdTCPServer ja multithreaded; sicher, dass du dir da keine Thread-Problematik eingehandelt hast? Wäre jetzt so mein Tipp... :nixweiss:

cu
Narses


GrubenPete - Mo 17.03.08 18:20

Hey, es lag an den Threads^^ Sorry, aber is das erste mal, dass ich so richtig mit den Indys arbeite.
Das Verbinden klappt jetzt wunderbar, jedenfalls beim ersten mal.

Danke trotzdem^^

Sascha


Jann1k - Di 18.03.08 00:18

Hi Narses,

ich versuche grade die Komponente zu installieren und halte mich dabei an dein Tutorial. Mein delphi 7 gibt mir auch die Meldung aus dass das Projekt neu kompiliert werden muss, klicke ich dann auf "Ja" kriege ich folgende Fehlermeldung :


Delphi-Quelltext
1:
[Fatal Error] dclusr.dpk(47): File not found: 'GIFCODE.dcu'                    


und das installieren der Komponente scheitert.

Zusätzlich kriege ich noch zwei Warnungen:



Delphi-Quelltext
1:
2:
3:
[Warning] dclusr.dpk(5): File not found: '..\..\..\..\dokumente und einstellungen\sebastian & martin\desktop\icq_20040630\icq\component\ICQClient.dcr' 

[Warning] dclusr.dpk(6): File not found: '..\..\..\..\Dokumente und Einstellungen\Sebastian & Martin\Desktop\icq_20040630\ICQ\Component\ICQDb.dcr'

Was tun?


Narses - Di 18.03.08 00:33

Moin!

user profile iconJann1k hat folgendes geschrieben:
klicke ich dann auf "Ja" kriege ich folgende Fehlermeldung :

Quelltext
1:
[Fatal Error] dclusr.dpk(47): File not found: 'GIFCODE.dcu'                    

und das installieren der Komponente scheitert.

Zusätzlich kriege ich noch zwei Warnungen:
Sieht aus, als wäre dein DefaultUserPackage zermatscht (du wirst vermutlich schon einige andere Komponenten hineininstalliert haben und diese möglicherweise nicht sauber deinstalliert oder Teile der Quellen verschoben). :nixweiss:

user profile iconJann1k hat folgendes geschrieben:
Was tun?
Du kannst die Komponente einfach in ein neues Package installieren oder das Default-Package (dcluser.dpk) löschen und ein Neues anlegen (wenn du sicher bist, dort keine Kompos drin zu haben, die du aktuell noch im Einsatz hast). :idea:

cu
Narses


Jann1k - Di 18.03.08 00:45

Zitat:
Sieht aus, als wäre dein DefaultUserPackage zermatscht


Gut zu wissen, worauf man beim nöchsten mal achten muss.


Zitat:
Du kannst die Komponente einfach in ein neues Package installieren oder das Default-Package (dcluser.dpk) löschen und ein Neues anlegen


Dankeschön, für die schnelle Hilfe - funktioniert problemlos.

Moderiert von user profile iconNarses: Delphi- durch Quote-Tags ersetzt


aenogym - Mi 09.04.08 22:24

Hi Narses,

erst einmal: vielen Dank für diese super Komponenten!
Jedoch habe ich ein sehr komisches Problem. Sämtliche per SendText() verschickte Nachrichten kommen doppelt bis vierfach an! Und wenn ich einen String sende, der länger als die maximale Datagrammgröße ist, dann wird jedes der aufgesplitteten Einzeldatagramme ebenfalls mehrmals gesendet!

Dieser Effekt tritt komischerweise nur bei meinem privaten PC auf (Delphi 7). Auf meinem Arbeitsrechner (Delphi 6) wird nichts doppelt versendet.

Kann sich das jemand erklären?

Dankbar,
aeno


Narses - Do 17.04.08 14:01

Moin!

user profile iconaenogym hat folgendes geschrieben:
erst einmal: vielen Dank für diese super Komponenten!
Danke für das Lob. ;)

user profile iconaenogym hat folgendes geschrieben:
Und wenn ich einen String sende, der länger als die maximale Datagrammgröße ist, dann wird jedes der aufgesplitteten Einzeldatagramme ebenfalls mehrmals gesendet!
Das ist klar, es wird ja intern auf mehrere Aufrufe runtergebrochen.

user profile iconaenogym hat folgendes geschrieben:
Sämtliche per SendText() verschickte Nachrichten kommen doppelt bis vierfach an!
Da du keinen Code oder konkretes Beispiel genannt hast, rate ich mal: du sendest Broadcasts und hast mehrere Schnittstellen? Dann ist das Verhalten zunächst mal "normal". Falle: bei einem Unicast an einen Host, dessen Adresse nicht aufgelöst werden kann, wird auf Broadcast umgeschaltet! :idea:

cu
Narses


Knulli - Di 07.10.08 12:10

Hi Narses,
ich glaub ich hab nen Bug gefunden...
Also auf einem Rechner läuft ein Client (mit UDPSockUtil), der im Sekundentakt was an einen Server (mit UDPSockUtil) auf einem anderen Rechner sendet. Weil der Client auch auf kleinere Kommandos des Servers auch reagieren soll, gibts da auch ein OnReceive-Eventhandler.

Wenn der Server aber nicht erreichbar ist, gibts im Client ein OnReceive-Ereignis obwohl niemand was gesendet hat. Und zwar immer unmittelbar nachdem er was gesendet hat.

Wenn ich in OnReceive die ReceivLength abfrage, steht 1 Byte drin, wenn ich aber danach mit ReceiveText das Byte abholen will um nachzusehen, was denn da so interessantes drinsteht, gibts ne Exception, die nicht mal durch Setzen des OnError Events unterdrückt werden kann.
Soll das so sein oder mache ich was falsch?
mfg Knulli

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
unit Client;
{**************************************************************************************************}
interface
{**************************************************************************************************}
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, UdpSockUtil, ExtCtrls;
{**************************************************************************************************}
type
  TfrmClient = class(TForm)
    Timer1: TTimer;
    UdpSockUtil1: TUdpSockUtil;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure UdpSockUtil1Receive(Sender: TObject);
    procedure UdpSockUtil1Error(Sender: TObject; Error: Integer);
  private
    bLaberSuelz: Boolean;
  public
  end;
{**************************************************************************************************}
var
  frmClient: TfrmClient;
{**************************************************************************************************}
implementation
{$R *.dfm}
{**************************************************************************************************}
uses
  WinSock;
{**************************************************************************************************}
procedure TfrmClient.FormCreate(Sender: TObject);
begin
  bLaberSuelz := false;
  UDPSockUtil1.LocalPort  := 12346;
  UDPSockUtil1.RemotePort := 12345;
  UDPSockUtil1.RemoteHost := '192.168.100.100';
  UDPSockUtil1.CloseInactiveSockets := true;
  UDPSockUtil1.Open();
  Timer1.Enabled := true;
end;
{**************************************************************************************************}
procedure TfrmClient.Timer1Timer(Sender: TObject);
var
  st: String;
begin
  if bLaberSuelz then st := 'Laber' else st := 'Sülz';
  bLaberSuelz := Not bLaberSuelz;
  UDPSockUtil1.SendText(st);
end;
{**************************************************************************************************}
procedure TfrmClient.UdpSockUtil1Error(Sender: TObject; Error: Integer);
begin
  // ShutUp exceptions
end;
{**************************************************************************************************}
procedure TfrmClient.UdpSockUtil1Receive(Sender: TObject);
var
  FromAddr: in_Addr;
  stCmd: String;
  Anzahl: Integer;
begin
  try
    Anzahl := UDPSockUtil1.ReceiveLength();
    if Anzahl > 0 then
    begin
      stCmd := UDPSockUtil1.ReceiveText(FromAddr);

      if stCmd = 'Hier spricht Dein Meister' then
        UDPSockUtil1.SendText('Ja, Chef...');
    end;

  except
    Windows.Beep(100010);
  end;
end;
{**************************************************************************************************}
end.


vladi4k - Di 07.10.08 12:40

Hallo,
ich hatte gleiches Problem wie Knulli
nur anders gelöst:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
//original
function TUdpSockUtil.ReceiveText(var RemoteAddr: in_addr): String;
begin
  SetLength(Result,ReceiveLength);
  SetLength(Result,ReceiveBuf(Pointer(Result)^,Length(Result),RemoteAddr));
end;


//neu
function TUdpSockUtil.ReceiveText(var RemoteAddr: in_addr): String;
begin
  SetLength(Result,ReceiveLength);

  if Result<>#0 then //nur wenn was drin ist
  SetLength(Result,ReceiveBuf(Pointer(Result)^,Length(Result),RemoteAddr))
  else //ansonsten Fehlermeldung

        if Assigned(FOnError) then
        FOnError(Self,WSAECONNRESET)
        //FOnError(Self,10054) // mit diesem Fehler melden
      else
        raise EUSUError.CreateFmt('Zielhost nicht erreichbar!',[]);

end;



Das Problem war das mein Programm immer abgestürzt hat wenn ich per Timer an ein Host sendete der nicht erreicht war UND in dieser Zeit Fenster von meinem Programm angeklickt habe (z.B. Fenster schieben oder Menü aufklappen). :(


:roll: Vladi

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt


Narses - Di 07.10.08 13:19

Moin!

user profile iconKnulli hat folgendes geschrieben Zum zitierten Posting springen:
Also auf einem Rechner läuft ein Client (mit UDPSockUtil), der im Sekundentakt was an einen Server (mit UDPSockUtil) auf einem anderen Rechner sendet. Weil der Client auch auf kleinere Kommandos des Servers auch reagieren soll, gibts da auch ein OnReceive-Eventhandler.

Wenn der Server aber nicht erreichbar ist, gibts im Client ein OnReceive-Ereignis obwohl niemand was gesendet hat. Und zwar immer unmittelbar nachdem er was gesendet hat.
Wird beim Senden jedes mal der Host aufgelöst oder arbeitest du immer mit einer festen IP-Adresse?

Das die WSA was zu einem nicht erreichbaren Host "zu sagen hat", ist erstmal normal. AFAIR wird da ein ICMP-Paket bei Ablehnung und ein internes Ereignis bei Nichterreichbarkeit ausgelöst, inwieweit das in Fensternachrichten (und welche) umgesetzt wird, kann ich aus der Kopf nicht sagen, muss mal in der WSA-Doku wühlen gehen... :lupe: :les:

user profile iconKnulli hat folgendes geschrieben Zum zitierten Posting springen:
Wenn ich in OnReceive die ReceivLength abfrage, steht 1 Byte drin,
Kann mich düster erinnern, dass der IOControl-Call nicht immer exakte Werte liefert (deshalb ja auch die Nachkorrektur beim Lesen), allerdings sollte da nie mehr als tatsächlich da ist, rauskommen... :? :gruebel:

Ich schau´s mir mal an. ;)

cu
Narses


Knulli - Di 07.10.08 13:44

Hi Narses,

Zitat:

Wird beim Senden jedes mal der Host aufgelöst oder arbeitest du immer mit einer festen IP-Adresse?

ich verwende feste IP Adressen:

Delphi-Quelltext
1:
UDPSockUtil1.RemoteHost := '192.168.100.100';                    


Sowohl Sender-PC (mehrere) als auch der Empfänger-PC bekommen von mir eine feste IP.
Server = Empfänger: 192.168.100.100
Client = Sender: 192.168.100.101 .. 192.168.100.199

gibt eigentlich schon eine neuere Version als V1.0.0?

mfg Knulli


delphi.crash - Di 31.03.09 22:20

hi,

ich weiß ich bin ein bisschen spät, aber super komponente!
mir stellt sich jetzt die frage, wie kann ich denn die ip eines antwortenden (bei mir) servers im OnReceive-event auflösen?

z.B. habe ich eine listbox und möchte den antwortenden auflisten:
via


Delphi-Quelltext
1:
2:
server:= UdpUtil1.RemoteAddress;
listbox.items.append(server);


funktioniert das logischerweise ja nicht :)

bin über jede hilfe dankbar,
greetz


Narses - Di 31.03.09 22:27

Moin und :welcome: im Forum!

user profile icondelphi.crash hat folgendes geschrieben Zum zitierten Posting springen:
wie kann ich denn die ip eines antwortenden (bei mir) servers im OnReceive-event auflösen?
Die Antwort auf diese Frage steht als Quelltext im ersten Beitrag dieses Threads [http://www.delphi-forum.de/viewtopic.php?t=55339]. :zwinker: Schonmal reingesehen? ;)

cu
Narses


delphi.crash - Di 31.03.09 22:30

jetzt wo dus sagst :D

danke


BlumenhunD - Do 21.05.09 20:10

Hallo !

hab deine kompo mal ausprobiert.
bei mir hat sie nur funktioniert wenn ich, selber einen LokalPort festgelegt habe.
ansonstent kommt socket error 10022 ( invalid argument )


Edit: wenn ich mit der kompo arbeite bekomm ich immer ne AccessViolation beim Schließen der Anwendung, egal ob ich bei OnClose .Free FreeAndNil() oder .Close garnix mache

Edit2: ich hab den fehler im Disassembler gefunden: call ntdll.ZwContinue
anscheinend will er vor der finalization noch ne datei aufrufen dei längst freigegeben ist.

Edit3: Der Fehler beim Schließen kommt nur, wenn ich etwas gesendet habe


Narses - Do 21.05.09 22:43

Moin und :welcome: im Forum!

Zeig mal deinen Code, mit deiner Beschreibung kann ich nix anfangen. :nixweiss: Welche Delphi-Version verwendest du?

cu
Narses


API - Fr 22.05.09 01:58

Hallo

Ich habe versucht, die Komponente unter Delphi 2009 zum Laufen zu bringen.
Jedoch werden beim Senden eines Strings zum Teil nicht korrekte Zeichen übertragen.
Ich nehme an, es gibt noch Problemstellen mit Ansi/Unicode.

Folgende Änderungen habe ich gemacht:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
42c42
<     FRemoteHost: String; // dahin senden
---
>     FRemoteHost: AnsiString; // dahin senden
60c60
<     procedure SetRemoteHost(const Value: String);
---
>     procedure SetRemoteHost(const Value: AnsiString);
90c90
<     property RemoteHost: String read FRemoteHost write SetRemoteHost;
---
>     property RemoteHost: AnsiString read FRemoteHost write SetRemoteHost;
226c226
<   FRemoteAddr.S_addr := INADDR_BROADCAST;
---
>   FRemoteAddr.S_addr := Integer(INADDR_BROADCAST);
369c369
<     FRemoteAddr.S_addr := INADDR_BROADCAST;
---
>     FRemoteAddr.S_addr := Integer(INADDR_BROADCAST);
383c383
<   if (Value.S_addr = INADDR_BROADCAST) then
---
>   if (Value.S_addr = Integer(INADDR_BROADCAST)) then
392c392
< procedure TUdpSockUtil.SetRemoteHost(const Value: String);
---
> procedure TUdpSockUtil.SetRemoteHost(const Value: AnsiString);
401,402c401,402
<       FRemoteAddr.S_addr := inet_addr(PChar(Value)); // IPdotdot?
<       if (FRemoteAddr.S_addr = INADDR_NONE) then begin // nein, DNSresolve
---
>       FRemoteAddr.S_addr := inet_addr(PAnsiChar(AnsiString((Value)))); // IPdotdot?
>       if (FRemoteAddr.S_addr = Integer(INADDR_NONE)) then begin // nein, DNSresolve
491c491
<         ToAddr.sin_addr.S_addr := INADDR_BROADCAST
---
>         ToAddr.sin_addr.S_addr := Integer(INADDR_BROADCAST)


API - Sa 23.05.09 07:16

Hat jemand eine Idee, wie ich die Komponente unter D2009 zum Laufen bringe?


Narses - So 24.05.09 23:30

Moin und :welcome: im Forum!

user profile iconAPI hat folgendes geschrieben Zum zitierten Posting springen:
Hat jemand eine Idee, wie ich die Komponente unter D2009 zum Laufen bringe?
Ich habe kein D2009, deshalb kann ich das nicht testen.

Nimm D7(pro), ist für Win32 eh das beste Delphi. ;)

cu
Narses


API - Di 26.05.09 19:34

Welches das beste Delphi ist 1. subjektiv und 2. kommt drauf an, was man machen möchte resp. muss.

Hat vielleicht sonst jemand eine Idee im DF?


Narses - Di 26.05.09 19:44

Moin!

user profile iconAPI hat folgendes geschrieben Zum zitierten Posting springen:
Welches das beste Delphi ist 1. subjektiv
Oh, das ist durchaus objektiv betrachtbar :| aber die Diskussion führt zu nichts, das ist wahr. ;)

user profile iconAPI hat folgendes geschrieben Zum zitierten Posting springen:
resp. muss.
Du wärst der erste, der D2009 nehmen "muss". :?

user profile iconAPI hat folgendes geschrieben Zum zitierten Posting springen:
Hat vielleicht sonst jemand eine Idee im DF?
Was stört dich an den Indy-Kompos, wenn du den TUdpSockUtil nicht zum Laufen kriegst? :nixweiss:

cu
Narses


Piranha - Mi 01.07.09 19:19

So, jetzt muss ich den Thread auch mal ausgraben.

Ich wollte ganz gerne mal die Broadcasts von UPnP einfangen. Aber irgendwie bekomm ich das nicht auf die Reihe. Mein Router castet von 192.168.1.1 auf 239.255.255.250 Port 1900. Standard halt. Doch was muss ich jetzt bei der UDP Komponente genau machen? Ich hab schon alle möglichen Kombinationen durchprobiert. Local-Port auf 1900, Remote auf 1900 oder Remote auf 1900 und Local auf 0 Remote Addr auf 255.255.255.255 oder auf 239.255.255.250 ... irgendwie kommt da nie was an.
Das da was ankommen müsste lässt sich an WireShark nachweisen.
Zur sicherheit von UPnP bin ich mir im klaren und das muss auch nicht in jedem Post erwähnt werden :D

Btw. Das was ankommt lasse ich einfach in einem Memo ausgeben.


Narses - Fr 03.07.09 11:34

Moin!

user profile iconPiranha hat folgendes geschrieben Zum zitierten Posting springen:
Mein Router castet von 192.168.1.1 auf 239.255.255.250 Port 1900. Standard halt.
Ich weiß noch nicht so genau, was du da machst, aber das oben ist nicht die Broadcastadresse des Netzes 192.168.1.1/8. :nixweiss: Das wäre 192.168.1.255. :idea:

cu
Narses


Piranha - So 05.07.09 18:42

uPnP Broadcastet immer auf 239.255.255.250 Port 1900... das wollte ich halt einfach mitlesen.

Hat sich jetzt eh erledigt, da ich gelesen hab das das Windows schon für mich macht und ich jetzt nurnoch mit der API kämpfen muss.


Narses - Di 23.02.10 22:38

Moin!

Kaum zu glauben aber wahr: ich habe mal die Anpassungen für Unicode-Delphi-Versionen eingebaut. Download im ersten Beitrag, wie immer. ;)

Kann das mal einer unter D2k9 testen? Ich habe nur ein D2010 zum Test hier. :nixweiss:

cu
Narses


Narses - Do 15.03.12 18:39

Moin!

Update auf v2.01, Milestone-Release, unbedingt die Doku ansehen! Details und Download wie immer im ersten Beitrag. ;)

cu
Narses


wdbee - Di 27.11.12 14:14

Hallo Narses,

bin gerade zufällig über diese Komponente gestolpert.
Da ich demnächst etwas in diese Richtung machen wollte, habe ich mir die Komponente herunter geladen und sie mal als Package installiert.

Was daran wichtig ist? Hehe, ich habe Delphi XE3!

Kurz und gut, (wie die Komponente,) nur in der Datei UdpSockUtil in der uses Anweisung "Messages" durch "Winapi.Messages" ersetzt und alles compiliert.

Werde das mal später mit den Demos testen.

Gruß

Wolf-Dieter


revenger - Mi 25.12.13 15:48

Hi,
leider habe ich ein Problem diese Komponente unter Delphi XE4 zu integrieren.

Bekomme beim installieren der Komponente folgende Fehlermeldung:

[dcc32 Fataler Fehler] dclusr.dpk(50): F1026 Datei nicht gefunden: 'C:\Program Files\Embarcadero\RAD Studio\11.0\lib\win32\release\UVersionInfo.dcu

Wäre schön wenn ich dafür eine Lösung finden würde, da ich gerne diese Komponente nutzen möchte.

Gruß und frohe Weihnachten!


Edit:
Ja, neee.. hab nicht darauf geachtet das ich noch andere sachen hinzugefügt hatte bei welchen er den pfad nicht mehr findet!

Alles gut soweit!


OlafSt - Do 26.12.13 01:07

Zur Vervollständigung: Die Komponente funktioniert ausgezeichnet unter XE4 und auch als 64-Bit.


OlafSt - Sa 13.02.16 22:04

Hallo Freunde,

heute hier mal etwas neues. Die UDP-Komponente funktioniert ausgezeichnet auch mit XE7 - das vorab. Aber ich habe hier ein Phänomen, von dem ich nicht so sicher bin, wie das in den Griff zu bekommen ist.

Nehmen wir eine Anwendung, die mehr oder minder regelmäßig via UDP Daten an ein Ziel schickt. Dies ist gar kein großes Problem und funktioniert stundenlang, tagelang, monatelang. Bis der Inhaber des Ziels auf die Idee kommt, seine feste IP gegen eine DynDNS auszutauschen, weil der Provider nun eine alle-24h-Zwangstrennung vornimmt.

Sobald das Ziel also zwangsgetrennt wurde (und sich automatisch via DynDNS wieder bekanntgibt) erreicht meine sendende Anwendung das Ziel nicht mehr. Die IP wird offenbar nur einmal ermittelt (was ich verstehe, ist ja auch aufwändig), durch das neuverbinden verändert sich die Ziel-IP, meine bisherige ist somit ungültig.

Einfache Lösung wäre nun, vom Ziel ein "ACK" zurücksenden zu lassen, doch ist dies eine Fremdanwendung, dieser Weg ist nicht möglich.

Hat jemand eine andere Option ?


jaenicke - So 14.02.16 00:54

Wenn du eine feste IP brauchst und sich das nicht anders lösen lässt (Neuverbindung anfordern, ...), bleibt wohl nur auch eine zu benutzen. Dafür könntest du einen virtuellen Server mieten und dort alle Daten 1:1 an deine dynamische Adresse weiterleiten. Das hätte auch den Vorteil, dass du dem Server auch einfach direkt mitteilen kannst, an welche IP er weiterleiten soll, so dass du auch kein DynDNS mehr extern brauchst.


OlafSt - Do 03.03.16 13:53

Eigentlich eine gute Idee, aber vermittel das mal einer Spedition, die keine Ahnung von sowas hat und die durch den eisenharten Wettbewerb jetzt nicht auch noch 2,99/Mon für einen virtuellen Server ausgeben will...

Ich habe mir den Source ein wenig genauer angesehen und kurzerhand ein Flag eingebaut, das die DNS-Auflösung zwangsweise immer wieder neu macht - wenn ich das so möchte. Zwecks Kompatibilität ist dieses Flag immer false, bestehender Code muß also nicht angepaßt werden.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
  TUdpSockUtil = class(TComponent)
  private
  [...]

    FRemoteHost: AnsiString; // dahin senden
    FRemoteAddr: in_addr; // nochmal als IP-Adresse
    FRemotePort: Word; // an diesen Port senden
    FForceResolve: boolean;  //Namensauflösung erzwingen - OST, 28.02.2016
  [...]
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  [...]
    property RemoteAddr: in_addr read GetRemoteAddr write SetRemoteAddr;
    property RecvFlags: Integer read FRecvFlags write FRecvFlags;
    property SendFlags: Integer read FSendFlags write FSendFlags;
    property ForceResolve: boolean read FForceResolve write FForceResolve;  //Resolve erzwingen - OST, 28.02.2016
  [...]
end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
constructor TUdpSockUtil.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Startup;
  [...]
  FRemotePort := 0;
  FCloseInactiveSockets := FALSE;
  FForceResolve:=false;  //Erzwungenes Hostname-Resolving default abgeschaltet - OST, 28.02.2016
  [...]
end;


Im wesentlichen habe ich die Entscheidung "wir haben den Hostnamen schon gesetzt" umgebaut: Alles bleibt beim alten, es sei denn, wir sind durch das Flag gezwungen.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
procedure TUdpSockUtil.SetRemoteHost(const Value: AnsiString);
var
   IP: in_addr;
   HostInfo: PHostEnt;
   ErrorCode: Integer;
begin
     //Bei not ForceResolve können wir bei unverändertem Hostnamen gleich raus - OST, 28.02.2016
     if (not FForceResolve) then
        if (FRemoteHost = Value) then
           exit;

     IP.S_addr := inet_addr(PAnsiChar(Value)); // falls der String bereits eine Adresse im IPdotdot-Format ist
     if (IP.S_addr <> Integer(INADDR_NONE)) or (Value = '255.255.255.255'then // sind wir schon fertig, übernehmen
     begin
          if (CheckAddr(IP)) then
          begin
               FRemoteHost := Value;
               FRemoteAddr := IP;
          end;
     end
     else
     begin
          if (Value <> ''then // wurde ein Host angegeben (Leerstring = localhost)
             HostInfo := WinSock.GetHostByName(PAnsiChar(Value)) // Name auflösen
          else
             HostInfo := WinSock.GetHostByName(NIL); // -> localhost abfragen
          if Assigned(HostInfo) then  // Auflösung OK?
          begin
               IP := PInAddr(HostInfo^.h_addr_list^)^;
               if (CheckAddr(IP)) then
               begin
                    FRemoteHost := Value;
                    FRemoteAddr := IP;
               end;
          end
          else
          begin
               ErrorCode := WSAGetLastError;
               if Assigned(FOnResolveError) then
                  FOnResolveError(Self, ErrorCode)
               else
                  raise EUSUError.CreateResFmt(PResStringRec(@sWindowsSocketError),
                                              [SysErrorMessage(ErrorCode), ErrorCode, 'GetHostByName']);
          end;
     end;
end;


Anschließend braucht es noch zwei weitere Ansatzpunkte: Das eigentliche Senden. Sowohl SendText als auch SendBuf setzen einfach den RemoteHost-Namen neu, wenn das Force-Flag gesetzt ist - was dann automatisch zur Neuauflösung führt.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function TUdpSockUtil.SendBuf(var Buf; BufSize: Integer): Integer;
begin
  FSocketLock.Enter;
  try
    //ggf. Host neu auflösen, wenn wir gezwungen sind - OST, 28.02.2016
    if (FForceResolve) then
       RemoteHost:=FRemoteHost;
    CreateBinding(FMainSocket, FLocalPort, FBroadcast);
    Result := InternalSendBuf(FMainSocket, Buf, BufSize, FSendFlags);
  finally
    CleanupSocket(FMainSocket);
    FSocketLock.Leave;
  end;
end;



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
function TUdpSockUtil.SendText(const S: AnsiString): Integer;
begin
    //ggf. Host neu auflösen, wenn wir gezwungen sind - OST, 28.02.2016
    if (FForceResolve) then
       RemoteHost:=FRemoteHost;
  Result := InternalSendText(FMainSocket, FLocalPort, FBroadcast, S);
end;


Bisherige Tests haben gezeigt, das es keinen ernsthaften Unterschied in der Laufzeit gibt und auch die Stabilität der UDP-Routinen an sich ist nicht betroffen - muß also gut gearbeitet haben.


Schwedenbitter - Mi 14.09.16 12:18

Ich muss dieses Thema mal aufwärmen:

Ich würde gern basierend auf TUdpSockUtil einen Chat-Programmieren. Das ist mit der Anleitung von Narses [https://www.entwickler-ecke.de/viewtopic.php?t=56272] eigentlich vergleichsweise einfach. Ich habe aber den Eindruck, dass mir Windows 10 gewaltig dazwischen funkt. So klappt schon der Beispielchat nicht unter Windows 10 - keine Fehlermeldungen, Exceptions oder dergleichen. Wenn ich einen oder mehrere Clients in einer VM (Windows XP) laufen lasse, klappt alles prima.

Interessant ist, dass die Clients unter Windows 10 die UDP-Pakete des XP-Clients empfangen können. Senden sie aber Pakete, scheint Windows 10 diese abzufangen. Sie gelangen also nicht mehr zu den XP-Clients. Bzgl. der Firewall wird man gleich nach dem Online-Gehen von Windows gefragt, ob das Programm im Netzwerk "funken" darf. Selbst das vollständige Abschalten der Windows-Firewall bringt nichts.
Ich habe schon zum Thema UDP und Windows 10 die Suchmaschinen bemüht. Aber eine Lösung oder einen Ansatz dazu habe ich leider nicht gefunden. Ich bin also ziemlich ratlos.

Hat jemand Ideen? Wo kann man dazu Näheres finden?

Gruß, Alex


jaenicke - Mi 14.09.16 13:31

Das Beispiel hatte bei mir unter Windows 10 abgesehen von den Multi-Screen Bugs (weil es in Delphi 7 kompiliert ist, ist das Fenster beim Starten außerhalb des Bildschirmbereichs) problemlos funktioniert.


Schwedenbitter - Do 15.09.16 08:07

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das Beispiel hatte bei mir unter Windows 10 abgesehen von den Multi-Screen Bugs (weil es in Delphi 7 kompiliert ist, ist das Fenster beim Starten außerhalb des Bildschirmbereichs) problemlos funktioniert.


Könntest Du mir bitte mal sagen, welches Windows 10 (also Professional/Home etc.)?

Wir haben hier 11 Rechner mit Windows 10 (alle Professional). 8 von denen noch mit Built 10586 und 3 mit 14393.
Ich habe dann gestern nochmal auf virtuellen Maschinen (XP, 7) und echten getestet. Überall läuft es prima, bloß unter den 10ern nicht.
Ich weiß, dass ist OT und aufgrund meiner Tests gehe ich davon aus, dass es ausnahmslos an Windows 10 liegt. Ich versuche bloß zu verstehen, warum das bei Deinem Windows 10 klappt und hier mit 11 Systemem nicht. Das ist merkwürdig.


jaenicke - Do 15.09.16 08:23

Das ist ebenfalls Windows 10 Professional.

Ist das Netzwerk bei euch als privates Netzwerk markiert? Vielleicht steht das auf öffentlich, wo dann standardmäßig stärker abgeschirmt wird.


Schwedenbitter - Do 22.09.16 17:12

Ich habe das Problem gefunden. Entschuldigt, dass ich die Pferde scheu gemacht habe und danke für Eure Hilfsbereitschaft!
Das Problem war/ist VirtualBox. Es legt einen virtuellen Netzerk-Adapter an mit einem anderen Subnetz (z.B. 192.168.56 statt 192.168.178). TUdpSockUtil nutzt nun diesen Adapter, womit die UDP-Pakete nicht mehr ankommen. Wenn ich jetzt von Hand die IP-Adresse des jeweiligen Adapters beim property BindTo eintrage, klappt es.
Allerdings hatte ich die ausführliche pdf-Datei zu TUdpSockUtil so verstanden, dass es hätte trotzdem klappen sollen/müssen, wenn man Brodcast := True setzt. Das tut es merkwürdiger Weise aber nicht.

Das Problem bringt mich zu einer weiteren Frage:
Wir haben 2 Standorte mittels 2 FritzBoxen via VPN verbunden. Diese haben daher notwendiger Weise ebenfalls 2 verschiedene Subnetze. Gäbe es dafür eine Lösung oder kann ich UDP gleich ad acta legen?

Ich hätte sonst erstmal versucht, ob die FritzBoxen überhaupt UDP-Pakete durchleiten.


Schwedenbitter - Mo 10.10.16 18:54

Ich muss leider nochmal pushen.

Ich komme mit unseren über VPN verbundenen Netzen nicht weiter. Es handelt sich dabei um zwei Subnetze mit 192.168.x.0. Innerhalb des nahen Subnetzes tut es ein Broadcast auf 192.168.x.255 bei der Maske 255.255.255.0. Leider komme ich möglicher Weise an den Routern nicht vorbei. Laut AVM wird innerhalb des VPN nichts geblockt. Damit müsste eigentlich ein Broadcast an 255.255.255.255 auch auf dem entfernten Subnetz ankommen, tut es aber nicht.

Zur Abhilfe war mein Plan daher, beim An- und Abmelden, statt eines Broadcast an alle möglichen Clients zu senden, die sich aus dem Adressbereich 192.168.x.y ergeben. Das dauert ca. 2 Sekunden, womit ich leben könnte. Es kommt aber nichts an - nicht einmal mehr im hiesigen Netz.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
For SNet:= 0 To 255 Do
Begin
  For IP:= 1 To 254 Do
  Begin
    UDPSocket.RemoteHost:= '192.168.' + IntToStr(SNet) + ' .' + IntToStr(IP);
    UDPSocket.SendText(SendText);
  End;
End;
Application.ProcessMessages;


Im Quellcode von UdpSockUtil.pas steht in Zeile 472 der Kommentar "// im Broadcast-Mode ist jede Adresse erlaubt, da auch Subnet-Broadcasts gehen". Interessant ist für mich der 2. Teil des Satzes.

Wie geht denn so ein Subnet-Broadcast?


Narses - Mo 10.10.16 22:12

Moin!

Klingt für mich wie ein Verständnisproblem mit IP-Netzen. :nixweiss:
user profile iconSchwedenbitter hat folgendes geschrieben Zum zitierten Posting springen:
Ich komme mit unseren über VPN verbundenen Netzen nicht weiter. Es handelt sich dabei um zwei Subnetze mit 192.168.x.0. Innerhalb des nahen Subnetzes tut es ein Broadcast auf 192.168.x.255 bei der Maske 255.255.255.0. Leider komme ich möglicher Weise an den Routern nicht vorbei. Laut AVM wird innerhalb des VPN nichts geblockt. Damit müsste eigentlich ein Broadcast an 255.255.255.255 auch auf dem entfernten Subnetz ankommen, tut es aber nicht.
Und das ist by-design so, es ist ein anderes Netz, also kann ein UDP-Subnet-Broadcast da nicht ankommen. Nur weil du eine Route definiert hast, wie (gerichtete) Pakete einen Netzübergang machen können, gilt das nicht für Nachrichten an ein Subnetz (=Broadcast). :idea: Üblicherweise filtert man darüber hinaus, selbst wenn das klappen sollte, UDP-Broadcasts an Routern raus, damit geschwätzige Protokolle nicht das Netz "zulabern". ;) (Routen definiert man üblicherweise über WAN-Stecken, die eine andere, meist deutlich schlechtere, Bandbreite haben) Kurz: Broadcasts kommen nur im gleichen Subnetz an (alles, was auf die Subnetmask passt, an die der Socket gebunden ist - deshalb heißt die so).

Um da irgendwas sinnvolles empfehlen zu können, habe ich zu wenig Durchblick, wie die Gegebenheiten bei euch sind und was da genau passieren soll. Da möchte ich lieber keine halbgaren Dunst-Empfehlungen aussprechen, das bringt nix. :?

cu
Narses


Schwedenbitter - Mo 17.10.16 20:58

Danke. OK. Das mit dem Broadcast habe ich verstanden - es geht nicht und ich werde es nicht ändern können.

Allerdings habe ich da eine weitere Frage: offenbar ist ein gerichtetes Senden per UDP möglich. Also das Senden eines UDP-Paketes an eine bekannte IP-Adresse im entfernten Netz. Ich habe das getestet und es klappt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
Procedure TMainForm.UDPSocketReceive(Sender: TObject);
Var
  Data        : TStringList;
  vonIP        : in_addr;
  Current      : TCmdToken;              // empfangenes Kommando
  I          : Integer;
  S          : String;
Begin
  Data:= TStringList.Create;
  Try
    Data.Text:= String(UDPSocket.ReceiveText(vonIP));// Daten auslesen
    If (Data.Count > 1Then              // mind. 2 Datenpakete
    Begin
      If (Data.Strings[0] = APP_ID) Then      // von unserem Client
      Begin
        Current:= GetCmdToken(Data.Strings[1]);
        If (Data.Count >= Succ(Syntax[Current].ArgCount)) Then
          Execute(Current, Data, vonIP);    // gültigen Befehl abarbeiten
      End;
    End
    Else
    Begin
      S:= '';
      For I:= 1 To Length(Data.Text) Do S:= S + IntToHex(Byte(Data.Text[I]), 2) + ' ';
      Loggen('''FREMDES PAKET: ' + Trim(S));
    End;
  Finally
    Data.Free;
  End;
End;

Wenn ich jetzt auf einem Linux-Rechner im entfernten Netz ein iperf --port 12345 --udp --num 100 --client 192.168.1.48 absetze, kommt das in meinem Netz hier an. Es sind zwar keine 1.470 Bytes, die iperf standardmäßig rübersendet, aber es kommt immerhin etwas an (FREMDES PAKET: FF FF FF FF 58 05 1D EE 0D 0A).


iperf bietet aber nicht nur einen Client, sondern auch einen Server an, der auf diesem Port lauschen kann. Wenn ich jetzt mit meinem Delphi-Programm

Delphi-Quelltext
1:
2:
UDPSocket.RemoteHost:= '192.168.255.35';
UDPSocket.SendText:= 'Blablablubb';
sende, kommt nichts an. Ich verstehe es so, dass RemoteHost den Empfänger enthält. Oder sehe ich das falsch?


Schwedenbitter - Mo 17.10.16 21:29

Ich nehme alles zurück! Die Pakete kommen auf dem Linux-Rechner an, wenn man die Firewall deaktiviert. Ich will wirklich nicht pushen. Ich schreibe bloß gleich, damit nicht jemand noch mehr in die falsche Richtung denkt.

Das verwirrt mich jetzt allerdings. Wenn man das Delphi-Programm in der IDE und auch isoliert startet, wird man unter (in meinem Fall) Windows 10 gefragt, ob man Traffic zulassen will. Das klicke ich brav an. Was kann man denn noch mehr machen?
Denn irgendwann wird es auch unpraktikabel. Wenn man ein Programm z.B. verkaufen will und dann zig Einstellungen ändern und das in ein Handbuch schreiben muss. Außerdem kommt das Paket an dem Rechner rein und es geht auch raus...
Jetzt bin ich völlig ratlos!


rage2002 - Do 09.03.17 13:05

Hallo
Vielen Dank für Deine Arbeit. Ich benutze einen MC mit unterschiedlichen Lan-Controllern und habe mir mit den üblichen UDP-Komponeten die Zähne ausgebissen ein einer Kommunikation am selben Port. Dank Deiner Komponente läuft es jetzt.

cu rage