Entwickler-Ecke

Internet / Netzwerk - UDPServer in einen Thread verlagern?


alias5000 - Sa 04.02.06 14:51
Titel: UDPServer in einen Thread verlagern?
[Im Stile eines alten Priesters bei der Predigt]
Liebe Brüdern und Schwestern

Ist es möglich, einen UDPServer, muss nichtmal mit Indy sein, wär aber toll, in einen Thread auszulagern?
Es geht darum, dass ich einen Chat habe, der ganz normal auf der MainForm (-->also läuft der Server im MainThread) seine Server und Client Komponenten hat (Indy 9).
Jetzt ist es aber so, dass im Chatprotkoll ein Befehl drinnen ist, auf den innerhalb einer bestimmten Zeit (~300 ms) geantwortet werden muss.
Im Normalbetrieb funktioniert das natürlich ohne Probleme, allerdings nicht in einer Situation:
-Wenn ein Client eine Form mit ShowModal anzeigt.
Dann werden die Ereignisse OnUDPRead erst nach dem schließen des Modalen Dialoges ausgelöst, was dann natürlich zu spät ist. Die Folgen sind ziemlich blöd: es ist dann einem anderen Benutzer möglich, mit demselben Nickname, wie man selber hat einzuloggen, was u.U. zu ganz netten Fehlern führen kann.

Es gibt natürlich eine Lösung, mit der das ganze funktionieren würde:
Ich zeige die Forms mit TFormXY.Show an und stelle FormStyle auf fsStayOnTop

Das finde ich aber nicht so schön, da es mehrere Uniterschiede zu ShowModal gibt:
-Die anderen Forms können weiterhin bedient werden
-Die Form wird immer oben angezeigt, egal, ob die Anwendung den Fokus hat, oder nicht, das will ich nicht.

Also die Idee, den UDPServer in einen Thread auszulagern, damit die Ereignisse zu jederzeit empfangen werden können.
Aber ich tippe mal, dass der TIdUDPServer von TComponent abstammt, und somit nicht direkt Thread-tauglich ist....

Was soll ich stattdessen tun?

Gruß alias5000


afk - Sa 04.02.06 16:04
Titel: Re: UDPServer in einen Thread verlagern?
user profile iconalias5000 hat folgendes geschrieben:
Also die Idee, den UDPServer in einen Thread auszulagern, damit die Ereignisse zu jederzeit empfangen werden können.
Aber ich tippe mal, dass der TIdUDPServer von TComponent abstammt, und somit nicht direkt Thread-tauglich ist....

Alle Komponenten stammen irgendwie von TComponent ab, alles andere sind Klassen, aber das sagt doch gar nichts über die Thread-tauglichkeit aus.

Bei manchen Komponenten (und auch bei Klassen) der VCL muß man mit Synchronize() arbeiten, wenn man aus Threads heraus auf sie zugreift (vor allem wenn das dann Bilschirmausgaben zur Folge hat), bei manchen muß man zusätzlich einen gleichzeitigen Zugriff aus verschiedenen Threads verhindern, z.B. mit einer CriticalSection, aber im Großen und Ganzen kann man viele Klassen und Komponenten auch in Threads verwenden.

Gerade bei einem UDPServer halte ich das sogar für ein absolutes Muß !

Gruß Axel


alias5000 - Sa 04.02.06 16:11

OK, werds mal testen :D
Bei Synchronize ist halt das Problem, dass das ganze dann wieder in den MainThread übergeht und somit nix gemacht würde.
Ja also falls da in der Sache schon jemand Erfahrung hat, würde es mich schon interessieren, ansonsten werde ich da mal ein Testprogramm für schreiben.

Gruß alias5000


afk - Sa 04.02.06 16:21

user profile iconalias5000 hat folgendes geschrieben:
Bei Synchronize ist halt das Problem, dass das ganze dann wieder in den MainThread übergeht und somit nix gemacht würde.

Nicht ganz, soweit ich weiß wird mit Synchronize die Ausführung zwar an den MainThread übergeben, damit er das nach/bei der Abarbeitung seiner Botschaftswarteschlange dann macht, diese Abarbeitung erfolgt aber ständig, auch wenn ein modales Fenster geöffnet ist, sonst wäre das modale Fenster nämlich auch nicht mehr bedienbar.

Daher werden die Hintergrundaktivitäten des Threads durch Synchronize zwar möglicherweise ein wenig gebremst, aber nicht blockiert.

Gruß Axel


alias5000 - Sa 04.02.06 16:26

Oh cool...
Aber warum werden dann die Ereignisse OnUDPRead so spät ausgelöst?


afk - Sa 04.02.06 16:34

user profile iconalias5000 hat folgendes geschrieben:
Aber warum werden dann die Ereignisse OnUDPRead so spät ausgelöst?

Mit den Indy-Komponenten kenne ich mich nicht wirklich aus, aber was heißt "so spät", und in welchem Zusammenhang (Programcode !) ?

Gruß Axel


alias5000 - Sa 04.02.06 16:45

Na Code kann ich hier nicht liefern, aber ich kanns dir erklären. Der Ablauf eines Programms sein so:

1.Programmstart, Anmelden zum Chat
2.ein Modales Fenster wird angezeigt
3.Ein anderer Client schickt eine Nachricht, um zu fragen, ob sein Nickname noch frei ist
4.Es wird noch kein Ereignis TidUDPServer.OnUDPRead ausgelöst, weil das Fenster noch modal angezeigt wird-> anderer Client loggt sich u.U. mit falschem Nick ein
5.Modales Fenster wird geschlossen
6.Erst jetzt werden die Ereignisse ausgeführt. Dabei werden sie in der Reihenfolge ausgelöst, in der sie während der Anzeige des Modalen Fensters empfangen wurden.
Leider ist es jetzt für den anderen Client zu spät

Wie es besser gewesen wäre, sollte ja klar sein, oder?

Ah Moment, mir fällt grad noch was auf, was ich mir genauer anschauen sollte:
Da gibts beim Server eine Property namens "ThreadedEvent". DAs könnte die Lösung bringen, mal in der Hilfe nachschauen...

EDIT: Indy benutzt für das Ereignis auch nur Synchronize, um es im MainThread asuführen zu lassen. Ich werde jetzt mal Threadad Event auf true setzen, ein paar Synchronize setzen, wenn nötig und so, sollte sich jetzt erstmal erledigt haben, danke dir afk!


Narses - Sa 04.02.06 17:01

Moin!

Falls du doch nicht unbedingt auf Indy setzen willst oder es nicht hinkriegst, schau dir mal das hier [http://www.delphi-forum.de/topic_TUdpSockUtil++UDPSocketWrapperKomponente++V100_55339.html] an. Damit geht´s auf jeden Fall, hab´s gerade getestet. :wink:

cu
Narses


alias5000 - Sa 04.02.06 17:38

Ja ich denk, ich werd bei Indy bleiben, weil ich damit doch recht gut zu recht komme und so eigentlich alles Funktioniert. Außerdem hab ich halt schon einen ziemlich großen Client, bei dem es sich einfach nimmer lohnen würde, ein neues System einzusetzen.
Es ist dagegen viel einfacher, den TidUDPServer.OnUDPRead in einem eigenen Thread laufen zu lassen und ggf. ein Synchronize bei bestimmten Stellen zu setzen.