Also, Leute, als nächstes werden wir die Implementierung von Unix-Domain-Sockets durchgehen, um unseren Server-Prozess zu implementieren.
Als Erstes müssen wir also den Quellcode herunterladen.
Stellen Sie also in Ihrem Linux-Terminal sicher, dass Sie mit dem Internet verbunden sind, und geben
Sie zum Herunterladen des Quellcodes den Befehl git clone as Http.
Gehen Sie zu github. com und dann CS-Praktika.
Und Serverdesign.
Beachten Sie also die Groß- und Kleinschreibung und drücken Sie einfach die Eingabetaste.
Mit diesem Befehl können Sie den Ordner "Serverdesign" herunterladen.
Gehen Sie nun in den Ordner, und hier sehen Sie ein Unix-Verzeichnis.
In diesem Verzeichnis befinden sich also die C-Dateien der Clients und des Servers.
Wir werden also die Datei server dot c besprechen, die den Server-Zustandsautomaten für Unix-Domain-Sockets
implementiert.
Also Leute, ich habe die Server-Dot-C-Datei geöffnet.
Wir werden also die Implementierungsdetails der Unix-Domain-Socket-Implementierung eines Server-Prozesses
durchgehen.
Sie können also die Standard-Header-Dateien hier einbinden.
Unix-Domain-Sockets haben also in der Regel einen Namen.
Als Erstes müssen Sie also eine Konstante oder ein Makro erstellen, das sich zu einer Zeichenkette erweitert.
Und diese Zeichenkette sollte innerhalb eines Systems so eindeutig sein, dass kein anderer Unix-Domain-Socket mit diesem Socket-Namen
bereits geöffnet ist.
Dies ist also der Socket-Name, den wir unserem Unix-Domain-Socket zuweisen werden, den wir erstellen
werden.
Richtig.
Der nächste definierte Wert ist die Puffergröße, d.h. 128 Byte ist die Puffergröße,
die unser Server verwenden wird, um Daten vom Client zu empfangen.
Bevor ich also auf die Hauptfunktion eingehe, möchte ich Ihnen in groben Zügen erklären, wie
unser Serverprozess genau funktioniert.
Also Leute, lasst mich euch die Funktionsweise des Serverprozesses erklären.
Das ist die eigentlich logische Funktionalität, die dieser Serverprozess implementiert.
Wir haben also einen Serverprozess, richtig?
Und nehmen wir an, es gibt einen Kunden.
C1 Unser Serverprozess versteht also zunächst nur die Zahlenwerte, die vom Client gesendet werden.
Angenommen, der Client sendet den Wert sechs, dann fügt der Serverprozess den Wert sechs zu seiner lokalen
Variable result hinzu und addiert den Wert sechs zu diesem Ergebniswert.
Nehmen wir nun an, der Client C1 sendet eine weitere Nachricht, sagen wir sieben, so dass der Serverprozess diese
Zeile ausführt und das Ergebnis auf sechs plus sieben aktualisiert wird.
Richtig.
Und noch einmal: Wenn der Client-Prozess C1 den Wert acht sendet und anschließend den Wert acht, neun,
zehn und so weiter, wird unser Server-Prozess weiterhin die vom Client gesendeten Werte hinzufügen.
Richtig.
Der Serverprozess antwortet also nicht mehr auf den Client.
Es werden lediglich die vom Client gesendeten Werte übernommen.
C1 Und sie berechnet die Summe dieser Werte.
In dem Moment, in dem der Client einen speziellen Wert Null an den Server sendet, gibt der Server das Ergebnis
zurück, das er bisher berechnet hat.
Der Server-Prozess gibt also das Ergebnis zurück, das 40 beträgt.
Dies ist also die einfache Funktionalität eines Serverprozesses, der die Summe aller ganzzahligen Werte
berechnet, die vom Client C1 an den Server gesendet werden.
Und in dem Moment, in dem der Client C1 den Wert Null an den Server sendet, bedeutet dies, dass der Client
C1 nun den Server auffordert, das bisher berechnete Ergebnis zurückzusenden.
Sobald der Server das Ergebnis an den Client zurückschickt.
Der Server schließt dann die Verbindung mit dem Client C1 und ist nun bereit, den neuen Satz von Werten von
einem neuen Client zu akzeptieren.
Da Sie nun die Funktionsweise eines Serverprozesses kennen, wird es Ihnen leicht fallen, die Serverimplementierung
oder den Servercode zu verstehen.
Wir gehen also direkt in die Hauptfunktion hinein.
Das erste, was Sie tun müssen, ist die Struktur zu nehmen, die von einem Standard-C-APIs und diese Struktur
ist struct sockaddr underscore u n, und die Variable dieser Struktur Typ ist Name bereitgestellt wird.
Wie wir also wissen, werden Unix-Domain-Sockets tatsächlich eindeutig durch einen Namen identifiziert.
Um also den Namen der Unix-Domain-Sockets zu speichern, müssen Sie eine Variable dieses Strukturtyps definieren.
Hier ist also die Definition dieser Struktur.
Sie sehen also, dass diese Struktur zwei Mitglieder hat.
Das erste Mitglied definiert die Adressfamilie Adressfamilie bedeutet, weil Sie die Unix-Domain-Sockets verwenden.
Daher wird der Wert des ersten Mitglieds, das Sun family ist, immer ein konstanter Wert sein, der in
den C-Standardbibliotheken definiert ist.
Und dieser Wert ist ein F-Unterstrich Unix und Sie müssen diesen Wert verwenden, um Unix-Domain-Sockets zu erstellen.
Und das zweite Mitglied ist eigentlich der Name des Unix-Domain-Sockets, richtig?
Wir haben also einige lokale Variablen übernommen.
Wir werden die Verwendung dieser lokalen Variablen im weiteren Verlauf der Diskussion unseres Codes erörtern.
Hier können Sie sehen, dass wir einen lokalen Speicher namens Buffer genommen haben.
Dieser Puffer wird vom Serverprozess verwendet, um die vom Client gesendeten Daten zu empfangen, und
er wird vom Serverprozess verwendet, um das Ergebnis nach der Berechnung der Ergebnisse an den Client zu
senden.
In Zeile 34 sehen Sie, dass Sie den Unix-Domain-Socket zerstören, wenn er bereits unter diesem
Namen erstellt wurde, denn Sie können nicht zwei Unix-Domain-Sockets mit demselben Namen erstellen.
Es könnte also sein, dass Sie bereits ein Unix-Domain-Socket-Programm auf demselben Rechner in einem anderen
Fenster ausführen.
Und wenn dieser Unix-Domain-Socket zufällig den gleichen Namen hat, dann wird dieser Server, wenn Sie diese bestimmte Instanz
des Server-Prozesses ausführen, diesen bestimmten Unix-Domain-Socket, der bereits
von einem anderen Programm im System erstellt wurde, tatsächlich zerstören und einen
Unix-Domain-Socket mit diesem Namen neu erstellen.
Und dieses Programm wird den Besitz dieses Unix-Domain-Sockets übernehmen.
Zeile 34 ist also eine Vorsichtsmaßnahme, damit Sie nicht zwei Unix-Domain-Sockets mit demselben Namen auf demselben Rechner ausführen
oder versuchen zu erstellen.
Gerade jetzt, wie wir wissen, dass der erste Schritt der Erstellung eines Unix-Domain-Server-Prozesses ist es, einen Master-Socket-Datei-Deskriptor
oder die wir auch als Verbindung Socket erstellen.
Wie Sie in diesem Flussdiagramm sehen können, besteht der erste Schritt des Serverprozesses darin, einen Socket zu erstellen.
In Zeile 39 können Sie sehen, dass wir einen Master-Socket-Dateideskriptor erstellt haben, den wir auch als
Verbindungs-Socket bezeichnen.
Und das erste Argument des Socket-Systemaufrufs ist der Typ des Sockets, den Sie erstellen.
In diesem Fall ist es also immer ein f Unterstrich Unix, richtig?
Das zweite Argument legt fest, ob es sich bei dem Socket oder der Art der Kommunikation, die Ihr Serverprozess mit dem
Client durchführt, um eine Stream-basierte Kommunikation oder eine Datagramm-basierte Kommunikation handelt.
Also hier, um zu.
Erstellen Sie eine Stream-basierte Kommunikation, müssen Sie den konstanten Wert übergeben, die sock underscore
stream ist.
Wenn Sie einen Server implementieren wollten, der auf Datagrammen basiert, dann hätten Sie sock underscore d
gram flag als zweites Argument an den Socket-Systemaufruf übergeben müssen.
Dann ist das dritte Argument nicht erforderlich und für diesen Kurs nicht diskussionswürdig.
Das dritte Argument können Sie also immer als Null oder Null übergeben.
Wenn also der Socket-Systemaufruf fehlschlägt, dann gibt er minus eins zurück.
Dies ist also der Code für die Fehlerbehandlung.
In Zeile 46 sind wir also in der Lage, einen Master-Socket-Dateideskriptor zu erstellen.
Richtig.
Der nächste Schritt, den der Serverprozess ausführt, ist also die Bindung.
Was bewirkt nun der Systemaufruf bind?
Bereiten wir uns also zunächst darauf vor, einen bind-Systemaufruf zu tätigen.
Dann werde ich erklären, was die Funktionalität von bind system call ist?
Erinnern Sie sich also daran, dass der Name die Variable vom Datentyp struct sockaddr underscore un war.
Wir initialisieren hier also nur die Namensvariable.
Und diese Struktur hatte, wie ich bereits erklärt habe, zwei Mitglieder.
Die erste ist die Familie.
Familienwert ist also immer ein f Unterstrich Unix.
Das zweite Element ist der Name des Sockets.
Mit STR und CP kopieren wir also den Namen des Sockets in diese Struktur.
Richtig.