Autor Beitrag
Bastler
Hält's aus hier
Beiträge: 11
Erhaltene Danke: 1



BeitragVerfasst: Mi 22.02.12 18:42 
Hallo Leute,

ich habe die Aufgabe, Daten eines Messgerätes zu visualiesieren. Das Messgerät verhält sich wie ein Server.. Man kann dem Gerät auf Schlüsselworte hin Daten entlocken. Man schickt beispielsweise ein "A" und erhält ein Antwort-Paket zurück. (Die Befehle sind durch $A getrennt) Die Kommunikation läuft über UDP. Die Kommunikation läuft in einem geschlossenen Netz ohne weitere Rechner (nur der Server und der Client).

Das Tool UDPSockutil von Narses wirkt schön schlank und übersichtlich. Ich möchte gern das Tool einsetzen. habe aber probleme damit.

Ideal wäre, wenn ich einen Befehl senden und sofort die Antwort auswerten könnte (ich will auf die Antworten reagieren können)
Ich nutze den Timer von Delphi und schicke in einem bestimmten Takt Sequenzen von Befehlen.

Jetzt das Problem:

- verwende ich den Eventbetrieb des Tools, kommt die erste Antwort erst, wenn die Timer-Routine komplett abgearbeitet wurde und dann in einem Rutsch hintereinander weg. (keine Reaktion möglich)
- verwende ich send und recieveString ohne Events in der Timer-Routine, dann passt die Antwort nicht zum Befehl. etwa so:
sende(A)
receive(-leer-)
sende(B)
receive(Antwort zu A)
Sende(C)
receive(Antwort zu b)
...

Hat jemand Erfahrung? Wo liegt mein Denkfehler?

Gruß

Udo
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 22.02.12 23:58 
Moin und :welcome: in der EE!

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
Hat jemand Erfahrung?
Aufzeig! ;) (zumindest mit der Komponente :P)

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
Ideal wäre, wenn ich einen Befehl senden und sofort die Antwort auswerten könnte (ich will auf die Antworten reagieren können)
Hier liegt dein "Denkfehler": UDP ist verbindungslos, es gibt keinen Zusammenhang zwischen verschiedenen Datenpaketen, auch nicht (oder erst recht nicht) bei Antworten auf Pakete. Es spielt dabei auch keine Rolle, ob nur diese beiden Geräte in einem Netz sind. :idea:

Wenn der embedded Controler keine Antwortkennung auf eine Anfrage anbietet, dann hast du ja nur das Timing als Zuordnungsmöglichkeit, und das ist bei UDP in einem hohen Takt wenig zuverlässig oder sinnvoll. :nixweiss:

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
- verwende ich den Eventbetrieb des Tools, kommt die erste Antwort erst, wenn die Timer-Routine komplett abgearbeitet wurde und dann in einem Rutsch hintereinander weg. (keine Reaktion möglich)
Das ist normal und liegt an der Ereignisverarbeitung von Windows. ;) Der Timer erzeugt beim Feuern ein Ereignis, und erst wenn dessen Handler abgearbeitet ist, wird der Handler für das Empfangsereignis aufgerufen.

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
- verwende ich send und recieveString ohne Events in der Timer-Routine, dann passt die Antwort nicht zum Befehl. etwa so:
sende(A)
receive(-leer-)
sende(B)
receive(Antwort zu A)
Sende(C)
receive(Antwort zu b)
...
Auch das ist "normal", du sendest Daten und willst sofort aus dem Socket lesen - da ist aber noch nix drin. :nixweiss: Dein Gerät muss erstmal das Paket kriegen, verarbeiten und was zurück senden, das dauert selbst bei einem sehr schnellen EC schon ein paar Millisekunden. :idea:

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
Man kann dem Gerät auf Schlüsselworte hin Daten entlocken. Man schickt beispielsweise ein "A" und erhält ein Antwort-Paket zurück. (Die Befehle sind durch $A getrennt)
Ich denke, hier liegt möglicherweise ein Schlüssel für das Problem: du hast das Protokoll des Gerätes möglicherweise noch nicht ganz oder gut genug verstanden. Aus dem einen Nebensatz kann ich aber auch nicht wirklich was erkennen. :?

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
Ich nutze den Timer von Delphi und schicke in einem bestimmten Takt Sequenzen von Befehlen.
Ansatz: verwende den asynchronen Modus der Komponente und benutze von mir aus auch den Timer. Allerdings musst du mehr ereignisorientiert denken: Im Timerereignis wird gesendet, im Empfangsereignis wird ausgewertet, nicht beides zusammen! ;) Stelle also beim Senden die Anfragen in eine Warteschlange ein und orientiere dich beim Empfangen daran.

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.

Für diesen Beitrag haben gedankt: Bastler
Bastler Threadstarter
Hält's aus hier
Beiträge: 11
Erhaltene Danke: 1



BeitragVerfasst: Do 23.02.12 11:27 
Moin, Moin!
Danke für die Denkanstöße und Tips! Insebesondere der Tip zur Warteschlange klingt interessant!
Ich muss meine "Denke" wohl wirklich mehr auf Ereignisorientierung umstellen!
Ich probiere es mal aus!

bye for now!

Udo
Bastler Threadstarter
Hält's aus hier
Beiträge: 11
Erhaltene Danke: 1



BeitragVerfasst: Do 23.02.12 20:30 
Beim Probieren bin ich in diesem Zusammenhang auf ein Problem mit dem Broadcast gestoßen. (Ziel vom Broadcast ist es bei mir zu prüfen, ob die Verbindung steht und die Ziel-IP zu ermitteln ). In meiner Testapplikation habe ich einen Button zum Senden von Schlüsselworten (s.o.) und einen der Button, der den Broadcast auslöst.
Senden funktioniert prächtig, der Broadcast liefert nichts zurück, obwohl WireShark anzeigt, dass das Gerät auf dem gleichen Port antwortet auf dem gesendet wurde (übrigens nicht auf Localport 40000)
Wieder ein Denkfehler?

Hier ein Codeauszug:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TForm1.FormCreate(Sender: TObject);
begin
   form1.UdpSockUtil1.LocalPort := 40000;
   form1.UdpSockUtil1.RemotePort:= 3490;
   form1.UdpSockUtil1.RemoteHost:= '192.168.1.88';
   form1.UdpSockUtil1.Open;
end;

// Nachricht an den angegebenen Host senden
procedure TForm1.BtnSendClick(Sender: TObject);
begin
  UdpSockUtil1.SendText(Input.Text+#$A);
end;

// Broadcast senden
procedure TForm1.Button1Click(Sender: TObject);
begin
  form1.UdpSockUtil1.BroadcastText(Input.Text+#$A);
end;


gruß

Udo

Moderiert von user profile iconMartok: Delphi-Tags hinzugefügt
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 23.02.12 23:27 
Moin!

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
Beim Probieren bin ich in diesem Zusammenhang auf ein Problem mit dem Broadcast gestoßen.
[...]
Senden funktioniert prächtig, der Broadcast liefert nichts zurück, obwohl WireShark anzeigt, dass das Gerät auf dem gleichen Port antwortet auf dem gesendet wurde (übrigens nicht auf Localport 40000)
Wieder ein Denkfehler?
Nein, das ist leider by-design so... :? Für den Broadcast wird ein zweiter Socket geöffnet (der dann einen anderen lokalen Port hat), weil man bei der WSA nicht transparent zwischen einem Uni- und einem Broadcast-Socket wechseln kann. :idea:

Um es kurz zu machen: Für diesen Zweck (Broadcast-Discover für ECs, die dann auf dem gleichen Port antworten), ist diese Komponente nicht geeignet. :nixweiss:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Bastler Threadstarter
Hält's aus hier
Beiträge: 11
Erhaltene Danke: 1



BeitragVerfasst: Do 23.02.12 23:47 
user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Für den Broadcast wird ein zweiter Socket geöffnet (der dann einen anderen lokalen Port hat), weil man bei der WSA nicht transparent zwischen einem Uni- und einem Broadcast-Socket wechseln kann.

mit dem zweiten lokalen Port kann ich leben. Wichtig ist, dass ich den gleichen Zielport verwenden kann. Kann ich die Komponente dann dazu bringen, den gefundenen EC zurückzumelden?

Gruß

Udo

Moderiert von user profile iconNarses: Zitat gekürzt.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 23.02.12 23:55 
Moin!

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
mit dem zweiten lokalen Port kann ich leben.
Nein, kannst du nicht, oder vielmehr, willst du nicht, das ist nämlich der Grund für das unerwünschte Verhalten. ;)

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
Wichtig ist, dass ich den gleichen Zielport verwenden kann. Kann ich die Komponente dann dazu bringen, den gefundenen EC zurückzumelden?
Wie ich schon schrieb, das geht im Moment mit der Komponente nicht. Dazu müsste der WSA der Broadcast-Port als Signalgeber für das Empfangsereignis mitgegeben werden, das kann man aber auch wieder nicht transparent umschalten (dämliche WSA :roll:). Ich habe das schon länger auf der ToDo-Liste :oops: so ist das nicht (du bist nicht der Erste, der mit der Kompo einen EC ansteuern möchte). Ich habe aber noch keinen wirklich guten Ansatz gefunden, wie man dieses Problem lösen kann. :nixweiss: Und deshalb: leider gibt´s da aktuell keine Möglichkeit über die Komponenten-API zu. Diesen Teil (Broadcast-Discover) müsstest du dann erstmal direkt über die WSA machen und dann erst mit einer IP für die Unicasts wieder auf der Kompo aufsetzen. :idea:

Ja, vorsichtig gesagt "unbefriedigend", leider habe ich bei der Entwicklung nicht bereits an diese Problematik bei EC-Discover-Tasks gedacht, so dass das jetzt im Nachhinein nicht mehr gut zu fassen ist, sorry. :|

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.

Für diesen Beitrag haben gedankt: Bastler
Bastler Threadstarter
Hält's aus hier
Beiträge: 11
Erhaltene Danke: 1



BeitragVerfasst: Fr 24.02.12 09:52 
Moin, Moin,

Schade, trotzdem Danke für die schnelle, umfassende Antwort!

Gruß

Udo
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 24.02.12 10:40 
Moin!

Hm :gruebel: mir ist da so über Nacht im Bettchen liegend eine Idee gekommen, vielleicht kann man das als "Workaround" billig umsetzen. Ich schau mir das mal am WE an, vielleicht habe ich am Montag was, womit man das gelöst kriegt. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 28.02.12 02:25 
Moin!

Es ist zwar nicht (mehr) Montag, dafür war es aber auch nicht "billig" umzusetzen... :nut: :lol: :| egal, war aber wohl langsam mal fällig. :nixweiss:

Hier vorab die Version 2.0 des TUdpSockUtil für dich zum Testen, bis ich die Anleitung aktualisiert habe, dann aktualisiere ich das auch im entsprechenden Thread. Changelog im Quelltext. Quick-Hints:
  • Der Betriebsmodus "Broadcast" ist jetzt nicht mehr eine Erweiterung des Unicast-Mode, sonder wirklich ein separater Betriebszustand! Das heißt, dass auch der Broadcast-Socket zum listening-socket im Broadcast-Mode wird. :gruebel: Kurzform: ;) damit sendet und empfängt die Komponente nun auch Broadcasts auf dem angegebenen lokalen Port. Setzt man also LocalPort und RemotePort gleich, dann erhält man jetzt endlich von einem spiegelnden UDP-Server die Datenpakete im Broadcast-Mode! :D Genau das, was du hier brauchst. :idea:
  • Fehlgeschlagene Hostnamensauflösungen führen jetzt nicht mehr zum Broadcast-Mode, sondern laufen auf ein neues Ereignis: OnResolveError, aktuell siehe Quelltext, demnächst auch in der Anleitung. :les:
  • Es gibt jetzt überladene Versionen der Lesemethoden, die auch den Absender-Port liefern. Dafür sind die Sende-/Empfangs-Flags jetzt als Komponenteneigenschaft untergebracht (wird wohl eh kaum einer benutzt haben). Hier könnten sich also ggfs. Deklarationsprobleme ergeben!
  • Einen ziemlich fiesen Bug totgeschlagen :suspect: Out-of-Resources bei CloseInactiveSockets auf FALSE
cu
Narses

//EDIT: Download der neuen Komponenten-Version in diesem Thread.

_________________
There are 10 types of people - those who understand binary and those who don´t.


Zuletzt bearbeitet von Narses am Do 15.03.12 18:41, insgesamt 2-mal bearbeitet

Für diesen Beitrag haben gedankt: Bastler
Bastler Threadstarter
Hält's aus hier
Beiträge: 11
Erhaltene Danke: 1



BeitragVerfasst: Di 28.02.12 20:31 
Moin, Moin!
das ist ja mal ein Service: eine neue Version zu meinem Problem!!

ich habe das Update installiert und damit gearbeitet. Ich bekomme tatsächlich ein Receive-Ereignis allerdings ist es leer. Hier mein Sourcebeispiel:
ausblenden 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:
procedure TForm1.FormCreate(Sender: TObject);
begin
  UdpSockUtil1.RemotePort := 3490;
  UdpSockUtil1.LocalPort  := 3490;
  UdpSockUtil1.Open;
  udpsockutil1.Listen := True;
end;

procedure TForm1.UdpSockUtil1Receive(Sender: TObject);
var
  vonIP : in_addr;
  puffer: String;
begin
 puffer := form1.UdpSockUtil1.ReceiveText(vonIP);
 Form1.Memo1.Lines.Add('Receive  '+IntToStr(Timecount)+' '+'  E: '+puffer+'     IP='+ inet_ntoa(vonIP));
end;

procedure TForm1.Button3Click(Sender: TObject);
Var abriss : boolean;
    vonIP : in_addr;
    port  : integer;

begin
  form1.UdpSockUtil1.Broadcast := True;
  form1.UdpSockUtil1.SendText('A'+#$A);
  form1.UdpSockUtil1.Broadcast := False;
end;
Wireshark zeigt, dass der Broadcast kommt und der Server antwortet. Leider ist die Antwort und die IP im Receive-Event leer.
Das Memofeld Memo1 zeigt:
Zitat:
Receive 0 E: IP=0.0.0.0

Wo hängt's?

Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 28.02.12 23:19 
Moin!

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
das ist ja mal ein Service: eine neue Version zu meinem Problem!!
:beer: Wie ich schon angedeutet habe, warst du jetzt nicht der Erste mit diesem Problem. Irgendwann hätte ich eh ran gemusst, da ich die Kompo natürlich auch selbst verwende und mich da schon länger einiges gestört hat. :nixweiss: Also, zur richtigen Zeit am richtigen Ort gewesen. ;)

user profile iconBastler hat folgendes geschrieben Zum zitierten Posting springen:
Wo hängt's?
Wie schon angedeutet ist das Konzept der API jetzt etwas anders.

So sollte das jetzt eigentlich laufen:
ausblenden volle Höhe 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:
// bei Programmstart
procedure TForm1.FormCreate(Sender: TObject);
begin
  UdpSockUtil1.LocalPort  := 3490;
  UdpSockUtil1.RemotePort := 3490;
  UdpSockUtil1.Broadcast  := True; // dauerhaft mit dem Broadcast-Mode arbeiten (erst ab v2.00 der Kompo!)
  UdpSockUtil1.Open; // Listener aktivieren (ab jetzt sind Ereignisse möglich)
end;

// Broadcast-Discover
procedure TForm1.Button1Click(Sender: TObject);
begin
  UdpSockUtil1.RemoteHost := '255.255.255.255'// Broadcast-Adresse für Broadcast-Sendungen
  UdpSockUtil1.SendText('A'+#$A); // ich schätze mal, das heißt "wer ist da?" ;)
end;

// Empfangsereignis
procedure TForm1.UdpSockUtil1Receive(Sender: TObject);
  var
    vonIP : in_addr;
    vonPort: Integer;
    puffer: String;
begin
 puffer := UdpSockUtil1.ReceiveText(vonIP, vonPort); // IP und Port beim Lesen mit abfragen
 Memo1.Lines.Add('Receive  '+IntToStr(Timecount)+' '+'  E: '+puffer+'  IP='+inet_ntoa(vonIP)+':'+IntToStr(vonPort));
end;

// Unicast-Senden
procedure TForm1.Button2Click(Sender: TObject);
begin
  UdpSockUtil1.RemoteHost := '192.168.0.1'// Unicast geht auch im Broadcast-Mode, hängt von der Adresse ab!
  UdpSockUtil1.SendText('B'+#$A); // das Kommando 'B' hab ich jetzt mal nur als Demo benutzt
end;
Ich bin gespannt. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Bastler Threadstarter
Hält's aus hier
Beiträge: 11
Erhaltene Danke: 1



BeitragVerfasst: Do 01.03.12 19:13 
Moin, Moin,

ich hab's endlich ausprobieren können und jawoll: es geht!!! :beer:
Heissen Dank! jetzt kann's losgehen mit der Kommunikation mit dem EC!

Gruß

Udo

Für diesen Beitrag haben gedankt: Narses
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: So 18.03.12 16:50 
Moin!

Falls du es übersehen haben solltest: es gibt jetzt hier das offizielle Release, du solltest die v2.0 besser nicht produktiv verwenden. :idea: ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.