4 Stimmen

Beliebige Zwei-Wege-UNIX-Socket-Kommunikation

Ich habe an einem komplexen Server-Client-System in C gearbeitet und bin mir nicht sicher, wie ich die Socket-Kommunikation implementieren soll.

Kurz gesagt ist das System eine Serveranwendung, die mit einer Datenbank kommuniziert und einen UNIX-Socket zur Kommunikation mit einem oder mehreren Kindprozessen verwendet, die mit fork() . Der Zweck der Kinder ist es, Spieleserver zu betreiben. Der Prozess des Starts eines Spieleservers läuft folgendermaßen ab:

  1. Der Server/"Manager" identifiziert einen Spielserver in der Datenbank, der erstellt werden soll. (Es wird davon ausgegangen, dass die Datenbankkommunikation bereits geordnet ist).
  2. Der Manager gabelt ein Kind (den "Spielleiter") auf.
  3. Der Gamecontroller richtet zwei Pipe-Paare ein, gabelt sich dann und ersetzt die stdin des Childs durch eine Pipe und die stdout und stderr durch eine andere Pipe.
  4. Das Kind des Spielcontrollers führt dann execlp() um die eigentliche ausführbare Datei des Spieleservers zu starten.

Meine Erfahrung mit Steckdosen ist relativ gering. Ich habe verwendet select() auf einer Server-Anwendung, bevor sie zahlreiche Clients "multiplexen" kann, wie das einfache Beispiel in der GNU C-Dokumentation zeigt ici .

Jetzt habe ich eine neue Herausforderung, denn das System muss mehr können: Der Manager muss in der Lage sein, willkürlich Befehle an die Kinder der Spielsteuerung zu senden (die er durch regelmäßiges Überprüfen der Datenbank findet) und Antworten zu erhalten, aber auch von ihnen eingehende beliebige Befehle/Fehler erwarten und Antworten zurücksenden.

Ich brauche also eine Art "Kontext"-System, bei dem die Sockets nur für sich selbst von Bedeutung sind. Mit anderen Worten, wenn ein Befehl vom Manager an den Spielcontroller gesendet wird, muss jede Partei wissen, wer fragt und was die Antwort ist (und daher, welcher Befehl es eine Antwort ist).

Denn select() ist nur nützlich, um zu wissen, wenn wir eingehende Daten haben, und ein Thread sollte auf sie blockieren, würde ich einen anderen Thread benötigen, die Daten sendet und die Antworten erhält? Erfordert dies, dass jeder Gamecontroller, obwohl er technisch gesehen ein "Client" ist, einen abhörenden Socket verwendet und mit select() auch?

Ich hoffe, ich habe das System und das Problem kurz und bündig erklärt; ich werde bei Bedarf weitere Einzelheiten hinzufügen. Danke!

1voto

frankc Punkte 10886

Ok, ich bin mir immer noch nicht ganz sicher, ob ich genau verstehe, wo dein Problem liegt, also werde ich einfach ein paar Dinge über das Schreiben einer Client/Server-Anwendung loswerden. Wenn ich neben der Spur bin, lassen Sie mich wissen.

  1. Damit der Server weiß, welche Clients zu welchem Socket gehören, teilen die Clients dies dem Server mit. Im Wesentlichen benötigen Sie ein Log-in-Protokoll. Wenn der Spielcontroller eine Verbindung zum Server herstellt, sendet er eine Nachricht, die besagt: "Hallo, ich registriere mich als Controller foo1 auf Host xyz, Port abc..." und was der Server sonst noch über seine Clients wissen muss. Der Server führt eine Datenstruktur, die Sockets auf Client-Metadaten, Status usw. abbildet. Wann immer er eine neue Nachricht erhält, kann er einfach den eingehenden Host/Port auf seine Metadaten abbilden. Oder Ihr Protokoll kann verlangen, dass der Client bei jeder eingehenden Nachricht den Namen, mit dem er sich registriert hat, als Feld sendet.

  2. Die Bearbeitung der Anfrage/Antwort kann auf verschiedene Weise erfolgen. Zunächst sollten wir uns mit dem Netzwerkteil auf der Serverseite befassen. Eine Möglichkeit, dies zu verwalten, ist, wie Sie erwähnt haben, die Verwendung von select (oder poll, oder epoll), um die Sockets zu multiplexen. Dies ist in der Regel der kompliziertere Weg, die Dinge zu tun. Eine andere Möglichkeit besteht darin, für jeden ankommenden Client einen Thread zu spawnen (oder einen Prozess zu forken, was heutzutage weniger üblich ist). Jeder dieser Threads kann den ihm zugewiesenen Socket lesen und Nachrichten einzeln beantworten, ohne sich um die Tatsache zu kümmern, dass es neben dem eigenen Client noch andere Clients gibt, mit denen er zu tun hat. Dieses einfache Eins-zu-eins-Thread-zu-Socket-Modell bricht zusammen, wenn es viele Clients gibt, aber wenn das nicht der Fall ist, dann ist es eine Überlegung wert.

Teil 2 behandelt eigentlich nur den Client, der dem Server eine Nachricht sendet, und den Server, der darauf antwortet. Was passiert, wenn der Server eine Kommunikation einleiten will? Wie macht er das und wie geht der Client damit um? Wie modellieren Sie außerdem die Kommunikation auf der Anwendungsebene, d. h. wenn wir den Lese-/Schreibteil beherrschen, woher wissen wir dann, was wir senden sollen? Wahrscheinlich werden Sie die Dinge in Form von Zustandsautomaten modellieren wollen. Es gibt noch viel mehr zu bedenken: Was passiert, wenn ein Client abstürzt? Was ist, wenn der Server abstürzt? Und was ist, wenn Sie unbedingt select verwenden wollen, weil Sie vielleicht viele Clients erwarten? Ich werde versuchen, dieser Antwort morgen mehr hinzuzufügen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X