Hallo in die Runde,
folgender Code funktioniert nicht wie gewünscht. Es scheint so, als wenn
der Backgroundworker nicht wirklich vom Mainthread getrennt ist.
Wie kann ich meinen Code so umschreiben, dass das Programm 2 Threads
hat?
1 Thread nimmt nur Verbindungen an und legt diese in einer Sammlung an
der 2 Thread geht diese Verbindungen zyklisch durch und schaut was für
Anfragen reingekommen ist und bearbeitet diese?
Hier mein Codevorschlag, der sich gegenseitig blockt.
1
privatestaticList<ClientHandle>Clients;//Sammelpool aller Clients
Das ist kein gutes Design. Ich mache das immer so:
Der erste Thread hört mit dem TCPListener an dem Port und wartet bis
eine Verbindung aufgebaut wird. Dann wird für jede neue Verbindung ein
Thread gestartet, der die ankommenden Daten bearbeitet. In dem
Lese-Thread solltest du blockierend lesen, also einfach warten bis Daten
kommen.
Wichtig ist noch Thread-Synchronisation beachten falls notwendig, d.h.
locks verwenden wenn Daten gleichzeitig verändert werden könnten und das
nicht thread-sicher möglich ist.
Ich bin gerade mit einem ähnlichen Thema beschäftigt. Ich habe einen
Proxy in C# geschrieben, der TCP Verbindungen annimmt und weiterleitet.
Dieser dient später dazu, Geräte im Heimnetz aus dem Internet heraus
erreichbar zu machen, ohne das die IP bekannt sein muss und vorallem
ohne das Portfreigaben etc. eingerichtet werden müssen. Ähnlich macht es
TeamViewer auch.
Fakt ist, dass das Programm nicht Thread basierend laufen kann, da die
Anzahl der Threads begrenzt ist. Daher kommen Async sockets zum Einsatz.
Aber auch da ist mir eine stabile Implementierung bisher leider noch
nicht gelungen. (Was echt frustrierend ist). Ich habe bisher auch noch
kein Beispiel gefunden, was wirklich stabil arbeitet. Mein Extremtest
ist meist auf dem Rechner, auf dem auch das Programm läuft, mittels
Browser direkt über 127.0.0.1 eine TCP Verbindung aufzubauen und F5
gedrückt zuhalten. ;-) Ja, dass ist Brutal, muss aber meiner Meinung
nach klappen, wenn später > 1000 Clients gehandled werden sollen.
Hat jemand vllt. hier eine Quelle für ein Beispiel, was zuverlässig
funktioniert?
Danke!
Fabian schrieb:> Hat jemand vllt. hier eine Quelle für ein Beispiel, was zuverlässig> funktioniert?
Nicht direkt, aber unter dem Stichwort "Service Bus" sollten Hinweise zu
finden sein (wenn man die ganzen Links zu Azure herausgefiltert hat).
Fabian schrieb:> Fakt ist, dass das Programm nicht Thread basierend laufen kann, da die> Anzahl der Threads begrenzt ist. Daher kommen Async sockets zum Einsatz.
OMG...
Async sockets sind letztlich auch nix anderes als Threads. Der
Unterschied ist bloß, dass du sie nicht selber erzeugen musst, sondern
dass das irgendwo "hinter den Kulissen" passiert.
Dirk schrieb:> Hallo, ich empfehle Dir erstmal den Blog> https://blog.stephencleary.com/2013/05/taskrun-vs-...
vielen Dank. Soweit würde ich das schon einmal richtung Tasks
umschreiben.
... schrieb:> Das ist kein gutes Design. Ich mache das immer so:>> Der erste Thread hört mit dem TCPListener an dem Port und wartet bis> eine Verbindung aufgebaut wird. Dann wird für jede neue Verbindung ein> Thread gestartet, der die ankommenden Daten bearbeitet. In dem> Lese-Thread solltest du blockierend lesen, also einfach warten bis Daten> kommen.>> Wichtig ist noch Thread-Synchronisation beachten falls notwendig, d.h.> locks verwenden wenn Daten gleichzeitig verändert werden könnten und das> nicht thread-sicher möglich ist.
Wie sehen die anderen das? Ist das Design wirklich murks? Der Server
soll ähnlich wie ein Chatserver funktionieren. Also ein Client schreibt
etwas und der Server soll das allen Clients mitteilen.
Wenn ich jetzt für jeden Client einen eigenen Thread habe müsste ich ja
immer jeden Clienthread invoken und anschließend dort die Nachricht
übergeben. Wird das so gemacht?
Fabian schrieb:> Ich bin gerade mit einem ähnlichen Thema beschäftigt. Ich habe> einen> Proxy in C# geschrieben, der TCP Verbindungen annimmt und weiterleitet.> Dieser dient später dazu, Geräte im Heimnetz aus dem Internet heraus> erreichbar zu machen, ohne das die IP bekannt sein muss und vorallem> ohne das Portfreigaben etc. eingerichtet werden müssen. Ähnlich macht es> TeamViewer auch.>> Fakt ist, dass das Programm nicht Thread basierend laufen kann, da die> Anzahl der Threads begrenzt ist. Daher kommen Async sockets zum Einsatz.> Aber auch da ist mir eine stabile Implementierung bisher leider noch> nicht gelungen. (Was echt frustrierend ist). Ich habe bisher auch noch> kein Beispiel gefunden, was wirklich stabil arbeitet. Mein Extremtest> ist meist auf dem Rechner, auf dem auch das Programm läuft, mittels> Browser direkt über 127.0.0.1 eine TCP Verbindung aufzubauen und F5> gedrückt zuhalten. ;-) Ja, dass ist Brutal, muss aber meiner Meinung> nach klappen, wenn später > 1000 Clients gehandled werden sollen.>> Hat jemand vllt. hier eine Quelle für ein Beispiel, was zuverlässig> funktioniert?>> Danke!
Genau so habe ich tatsächlich auch getestet. Ich schreibe mir jetzt
wirklich einen TCP Client und nehme nicht den Browser. Ich vermute, dass
der irgendwie kein passendes Abschlusszeichen sendet und mein Code daher
ewig im Read hängt.
csharper schrieb:> Hallo in die Runde,>> folgender Code funktioniert nicht wie gewünscht. Es scheint so, als wenn> der Backgroundworker nicht wirklich vom Mainthread getrennt ist.>
Kannst du das bitte mal genauer definieren? Was funktioniert denn nicht
wie gewünscht.
Das einzige was ich sehen kann ist, dass handlethread_ProgressChanged
nicht aufgerufen wird, weil du ReportProgress in deiner DoWork nicht
aufrufst.
Keiner N. schrieb:> csharper schrieb:>> Hallo in die Runde,>>>> folgender Code funktioniert nicht wie gewünscht. Es scheint so, als wenn>> der Backgroundworker nicht wirklich vom Mainthread getrennt ist.>>>> Kannst du das bitte mal genauer definieren? Was funktioniert denn nicht> wie gewünscht.> Das einzige was ich sehen kann ist, dass handlethread_ProgressChanged> nicht aufgerufen wird, weil du ReportProgress in deiner DoWork nicht> aufrufst.
Tatsächlich scheint in meinem obigen Code gar kein Fehler enthalten zu
sein.
Mein Problem war wohl die Receivedata Funktion:
Erster Versuch war(blockiert und freezed den Prozess):
Hallo,
>Wie sehen die anderen das? Ist das Design wirklich murks? Der Server>soll ähnlich wie ein Chatserver funktionieren. Also ein Client schreibt>etwas und der Server soll das allen Clients mitteilen.
Mit diesen Informationen würde ich sagen deine Implementierung ist nicht
gut gewählt.
Ich vermute dein Server/Host ist eio Windowsrechner, dann emfpehle ich
Dir WCF, ob SelfHosted oder direkt im System gehostet entscheidet
überwiegend die Stabiliätsfrage.
Hier ein Beispiel, aber du findest unzählige Beispiele zu diesem Thema.
https://www.codeproject.com/Articles/25261/A-WCF-WPF-Chat-Application
... schrieb:> Das ist kein gutes Design. Ich mache das immer so:>> Der erste Thread hört mit dem TCPListener an dem Port und wartet bis> eine Verbindung aufgebaut wird. Dann wird für jede neue Verbindung ein> Thread gestartet, der die ankommenden Daten bearbeitet. In dem> Lese-Thread solltest du blockierend lesen, also einfach warten bis Daten> kommen.>> Wichtig ist noch Thread-Synchronisation beachten falls notwendig, d.h.> locks verwenden wenn Daten gleichzeitig verändert werden könnten und das> nicht thread-sicher möglich ist.
Das ist die ebenso klassische wie korrekte Lösung, und ich verstehe
nicht, wie Dir jemand dafür ein "nicht lesenswert" geben kann. Es fehlen
nur zwei Hinweise: erstens, daß die maximale Anzahl der Threads
konfigurierbar sein sollte, um möglichen DoS-Angriffen entgegenzuwirken,
und zweitens, daß die Connectionhandler aus demselben Grund einen
Timeout haben sollten.
c-hater schrieb:> Async sockets sind letztlich auch nix anderes als Threads. Der> Unterschied ist bloß, dass du sie nicht selber erzeugen musst, sondern> dass das irgendwo "hinter den Kulissen" passiert.
Das ist so nicht richtig. Bei asynchroner Programmierung wird meist mit
einer eventloop gearbeitet, genau das gleiche macht man, wenn man in C
mit epoll (bevorzugt), poll oder select programmiert. Die Verwaltung von
TCP-Verbindungen ist nicht wirklich aufwändig, sodass man das gut in nur
einem Thread erledigen kann.
Was allerdings ein legitimes Mittel ist: Die eigentliche Arbeit
(Berechnungen etc) in einen Threadpool auszulagern, das minimiert die
Stellen, an denen du zwischen Threads und zwischen dem
Verbindungs-Thread und den Worker-Threads synchronisieren musst.
Hier mal ein Tutorial für epoll()
https://kovyrin.net/2006/04/13/epoll-asynchronous-network-programming/.
Das Konzept ist auch in C#, Python etc. ähnlich.
Martin K. schrieb:> c-hater schrieb:>> Async sockets sind letztlich auch nix anderes als Threads. Der>> Unterschied ist bloß, dass du sie nicht selber erzeugen musst, sondern>> dass das irgendwo "hinter den Kulissen" passiert.>> Das ist so nicht richtig.
Doch, ist es. Auf jeden Fall im Falle von C# in der .Net-Umgebung und
das war das Thema...
> Bei asynchroner Programmierung wird meist mit> einer eventloop gearbeitet
Eine EventLoop ist NICHT ansynchron, kann es nicht sein. Allein der
Begriff "loop" darin zeigt das nur zu deutlich. Eine Schleife ist
nämlich eine Kontrollstruktur, die es nur synchron geben kann.
Natürlich können asynchrone Zustandsänderungen auf den Scheiss in der
Schleife einwirken, aber nur, wenn diese Zustandsänderungen asychron
generiert werden (also in Threads oder ISRs) UND die Schleife durch
Polling der Zustände davon erfährt.
> Die Verwaltung von> TCP-Verbindungen ist nicht wirklich aufwändig, sodass man das gut in nur> einem Thread erledigen kann.
Ja, genau deswegen machen das wohl alle modernen Betriebssysteme seit
Jahrzehnten genau NICHT so...
Natürlich finden sich aber immer wieder dumme Anfänger, die den Support
moderner OS nicht nutzen, weil sie mit der Programmierung paralleler
Abläufe schlicht hoffnungslos überfordert sind und deshalb irgendwelche
Polling-Ansätze nutzen, die die OS' seit Jahrzehnten allein deshalb
mitschleppen, um eben diesen Typen auch eine kleines Erfolgserlebnis zu
ermöglichen...
Finster, aber die blanke Wahrheit.