So senden Sie Nachrichten über einen Kanal

7

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.

    
Jin Hoon Jeffrey Bang 05.04.2016, 04:35
quelle

3 Antworten

19

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:

Wenn die Anzahl der Listener bekannt ist

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%

Wenn die Anzahl der Listener nicht bekannt ist

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:

%Vor%

Wann immer Sie einen Arbeiter starten möchten:

%Vor%

Und Ihr Disponent wird geändert in:

%Vor%

Letzte Wörter: Lassen Sie niemals eine baumelnde Goroutine stehen

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:

%Vor%

Und wenn wir einen Worker erstellen, weisen wir ihm den globalQuit -Kanal als Quit-Signal zu:

%Vor%

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:)

    
nevets 05.04.2016, 05:48
quelle
1

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:

  • Sie können einen Statuswechsel mit sync.Cond übertragen. Auf diese Weise haben Sie nach dem Setup keine Allokierung, aber Sie können keine Timeout-Funktion hinzufügen oder mit einem anderen Kanal arbeiten.
  • Sie können eine Änderung des Freigabezustands mit einem geschlossenen alten Kanal übertragen und einen neuen Kanal und sync.Mutex erstellen. Auf diese Weise gibt es eine Zuweisung pro Statusänderung, aber Sie können die Funktion für die Zeitüberschreitung hinzufügen und mit einem anderen Kanal arbeiten.
  • Sie können Broadcasts an ein Stück Funktions-Callback senden und sync.Mutex verwenden, um sie zu verwalten. Der Anrufer kann Channel-Sachen machen. Auf diese Weise haben Sie mehr als eine Zuweisung pro Anrufer und arbeiten mit einem anderen Kanal.
  • Sie können zu einem Kanalabschnitt senden und sync.Mutex verwenden, um sie zu verwalten. Auf diese Weise haben Sie mehr als eine Zuweisung pro Anrufer und arbeiten mit einem anderen Kanal.
  • Sie können zu einem Stück sync.WaitGroup senden und sync.Mutex verwenden, um sie zu verwalten.
bronze man 12.08.2017 03:30
quelle
0

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.

    
Rick-777 05.04.2016 13:45
quelle

Tags und Links