Ich bin neu und möchte einen einfachen Chat-Server erstellen, auf dem Clients Nachrichten an alle verbundenen Clients senden können.
In meinem Server habe ich eine Goroutine (unendlich für Schleife), die Verbindung akzeptiert und alle Verbindungen von einem Kanal empfangen werden.
%Vor%Dann starte ich einen Handler (goroutine) für jeden verbundenen Client. Im Handler versuche ich, über den Kanal zu allen Verbindungen zu senden.
%Vor%Ich kann jedoch nicht senden, weil (ich denke beim Lesen der Dokumente) der Kanal vor dem Iterieren geschlossen werden muss. Ich bin nicht sicher, wann ich den Kanal schließen sollte, weil ich ständig neue Verbindungen akzeptieren will und das Schließen des Kanals das nicht zulassen wird. Wenn jemand mir helfen kann oder eine bessere Möglichkeit bietet, Nachrichten an alle angeschlossenen Kunden zu senden, wäre es sehr hilfreich.
Was Sie tun, ist ein Fan-Out-Muster, das heißt, mehrere Endpunkte hören auf eine einzige Eingangsquelle. Das Ergebnis dieses Musters ist, dass nur einer dieser Listener die Nachricht erhalten kann, wenn eine Nachricht in der Eingabequelle ist. Die einzige Ausnahme ist ein close
des Kanals. Dieser close
wird von allen Listenern erkannt und somit ein "Broadcast".
Aber was Sie tun möchten, ist das Senden einer Nachricht, die von der Verbindung gelesen wird, also könnten wir etwas wie folgt machen:
Lassen Sie jeden Mitarbeiter den dedizierten Broadcast-Kanal hören und senden Sie die Nachricht vom Hauptkanal an jeden dedizierten Broadcast-Kanal.
%Vor%Und dann könnten wir einen Haufen Arbeiter haben:
%Vor%Dann starten Sie unseren Hörer:
%Vor%Und ein Dispatcher:
%Vor% In diesem Fall funktioniert die oben angegebene Lösung immer noch. Der einzige Unterschied besteht darin, dass Sie, wenn Sie einen neuen Mitarbeiter benötigen, einen neuen Mitarbeiter erstellen, ihn starten und dann in workers
slice schieben müssen. Aber diese Methode erfordert eine thread-sichere Scheibe, die eine Sperre um sie benötigen. Eine der Implementierungen könnte wie folgt aussehen:
Wann immer Sie einen Arbeiter starten möchten:
%Vor%Und Ihr Disponent wird geändert in:
%Vor% Eine der guten Praktiken ist: Lass niemals eine baumelnde Goroutine stehen. Wenn du mit dem Hören fertig bist, musst du alle von dir gefeuerten Goroutinen schließen. Dies geschieht über quit
channel in worker
:
Zunächst müssen wir einen globalen quit
Signalisierungskanal erstellen:
Und wenn wir einen Worker erstellen, weisen wir ihm den globalQuit
-Kanal als Quit-Signal zu:
Wenn wir dann alle Arbeiter ausschalten wollen, tun wir einfach:
%Vor% Da close
von allen hörenden Spielern erkannt wird (das ist der Punkt, den Sie verstanden haben), werden alle Goroutinen zurückgegeben. Denken Sie daran, Ihre Dispatcher-Routine ebenfalls zu schließen, aber ich überlasse es Ihnen:)
Senden Sie an ein Segment des Kanals und verwenden Sie sync.Mutex, um das Hinzufügen und Entfernen von Kanälen zu verwalten. Dies könnte der einfachste Weg in Ihrem Fall sein.
Hier können Sie broadcast
in golang tun:
Da Go-Kanäle dem CSP-Muster (Communication Sequential Processes) folgen, sind Kanäle eine Punkt-zu-Punkt-Kommunikationseinheit. An jedem Austausch ist immer ein Autor und ein Leser beteiligt.
Jedoch kann jeder Kanal Ende zwischen mehreren Goroutinen geteilt sein. Das ist sicher - es gibt keine gefährlichen Wettlaufbedingungen.
Es kann also mehrere Autoren geben, die sich das Schreibende teilen. Und / oder es können mehrere Leser das Leseende teilen. Ich schrieb mehr dazu in einer anderen Antwort , die enthält Beispiele.
Wenn Sie wirklich eine Übertragung benötigen, können Sie dies nicht direkt tun, aber es ist nicht schwer, eine Zwischen-Routine zu implementieren, die einen Wert in jede einer Gruppe von Ausgabekanälen kopiert.