Socket-Programmierung in C++

Socket Programmierung In C



Socket-Programmierung ist zu einem wichtigen Thema im Bereich der Computernetzwerke geworden. Dabei wird eine Verbindung zwischen zwei Knoten, Server und Client, hergestellt, um unterbrechungsfrei miteinander zu kommunizieren. Der Server fungiert als Listener im Kommunikationskanal und lauscht dem Client an einem bestimmten Port an einer IP-Adresse. Andererseits fungiert der Klient als Kommunikator im Kommunikationskanal. Der Client kontaktiert den Server, um eine Verbindung herzustellen und Kontakt mit dem Server aufzunehmen. Ziel dieses Artikels ist es, einen umfassenden und detaillierten Leitfaden zur Socket-Programmierung in C++ bereitzustellen, der die Grundlagen abdeckt, praktische Beispiele vorstellt und eine detaillierte Erklärung des Codes liefert.

Etablierung des Client-Server-Modells

Socket-Programmierung ist der Prozess, der mithilfe von Sockets einen Kommunikationskanal zwischen dem Server und dem Client aufbaut. Im folgenden Beispielcode startet der Client einen Kontakt mit dem Server und der Server wird so eingerichtet, dass er die Clientverbindungen akzeptiert. Lassen Sie uns die Server- und Client-Codesegmente verstehen, indem wir ihre Kernfunktion innerhalb der Netzwerkkommunikation demonstrieren. Das Folgende ist der serverseitige Code. Lassen Sie uns zuerst den Code sehen und ihn dann Punkt für Punkt im Detail erklären.

1. Serverseitig







Der Code für die Serverseite des Modells ist im Folgenden angegeben. Lassen Sie uns sehen, was im Code passiert:



#include
#include
#include
#include

verwenden Namensraum std ;

#define PORT 8080
#define MAX_BUF_SIZE 1024

int hauptsächlich ( ) {
int ser_socket, cli_socket ;
Struktur sockaddr_in ser_address, cli_address ;
verkohlen buf [ MAX_BUF_SIZE ] = { 0 } ;

Wenn ( ( ser_socket = Steckdose ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
Fehler ( „Fehler bei der Socket-Erstellung“ ) ;
Ausfahrt ( EXIT_FAILURE ) ;
}

ser_address. sin_family = OF_INET ;
ser_address. sin_addr . s_addr = INADDR_ANY ;
ser_address. sin_port = htons ( HAFEN ) ;

Wenn ( binden ( be_socket, ( Struktur sockaddr * ) & ser_address, Größe von ( ser_address ) ) == - 1 ) {
Fehler ( „Fehler beim Binden“ ) ;
Ausfahrt ( EXIT_FAILURE ) ;
}

Wenn ( Hören ( be_socket, 3 ) == - 1 ) {
Fehler ( „Konnte nicht zuhören“ ) ;
Ausfahrt ( EXIT_FAILURE ) ;
}

cout << „Server lauscht auf Port“ << HAFEN << „... \N ' ;

socklen_t cli_address_len = Größe von ( cli_address ) ;
Wenn ( ( cli_socket = akzeptieren ( be_socket, ( Struktur sockaddr * ) & cli_address, & cli_address_len ) ) == - 1 ) {
Fehler ( „Annahme fehlgeschlagen“ ) ;
Ausfahrt ( EXIT_FAILURE ) ;
}

lesen ( cli_socket, buf, MAX_BUF_SIZE ) ;
cout << „Die Botschaft des Kunden lautet:“ << buf << endl ;

schicken ( cli_socket, „Nachricht des Servers“ , strlen ( „Nachricht des Servers“ ) , 0 ) ;

schließen ( cli_socket ) ;
schließen ( ser_socket ) ;

zurückkehren 0 ;
}

Das angegebene Beispiel ist der serverseitige Code des C++-Programms. Dieser Code funktioniert für einen einfachen TCP-Server, der auf Verbindungen an einem einzelnen bestimmten Port lauscht. Wenn eine Verbindung erfolgreich hergestellt wurde, erhält der Server eine Nachricht, die vom Client gesendet wird. Anschließend wird es auf der Konsole ausgedruckt und eine Antwortnachricht an den Client gesendet. Lassen Sie uns jede Codezeile verstehen.



Das Programm beginnt mit der Einbindung der Bibliotheken: „iostream“ für Standard-Eingabe-/Ausgabedefinitionen, „cstring“ für String-Verarbeitungsfunktionen, „unistd.h“ für den Zugriff auf die POSIX-Betriebssystem-API und „arpa/inet.h“ für Führen Sie die Internetoperationen durch. Die Anweisung „#define PORT 8080“ bedeutet, dass sie die Portnummer 8080 definiert, an der der Server lauscht. „#define MAX_BUF_SIZE 1024“ bedeutet die maximale Puffergröße für die eingehenden Daten, die 1024 beträgt.





In der Hauptfunktion werden zwei Variablen initialisiert, „ser_socket“ und „cli_socket“, um sowohl den Server als auch den Client darzustellen. Die anderen drei Variablen „sockaddr_in“, „ser_address“ und „cli_address“ vom Typ „struct“ werden als Adressstrukturen für den Server und den Client initialisiert. Danach wird ein Puffer namens „buf“ initialisiert, der die vom Client kommenden Daten speichert.

Die Funktion socket() in der Bedingung „if“ erstellt einen neuen TCP-Socket. AF_INET bezeichnet IPv4, SOCK_STREAM stellt den verbindungsorientierten und zuverlässigen TCP-Socket dar, das letzte Argument, das 0 ist, wird zur Auswahl des Standard-TCP-Protokolls angegeben, INADDR_ANY akzeptiert die Verbindungen auf jeder IP-Adresse und htons (PORT) konvertiert die Portnummer aus dem Host-Byte-Reihenfolge in die Netzwerk-Byte-Reihenfolge umwandeln.



Da alles richtig definiert ist, besteht der nächste Schritt darin, den Server als Lister am angegebenen Port einzurichten und die Verbindungen auf jeder Netzwerkschnittstelle zu akzeptieren. Der Socket wird mit den Informationen in „ser_address“ durch die Methode bind() angegeben. Wir geben eine Fehlermeldung aus und beenden den Vorgang, wenn die Bindung fehlschlägt. Die Funktion „accept()“ öffnet einen neuen Socket für die Verbindung mit dem Client, während die Funktion „listen()“ den Server anweist, auf eingehende Verbindungen zu warten. Wenn die Funktion „accept()“ fehlschlägt, wird die Fehlermeldung gedruckt und die Funktion wird beendet.

Als nächstes liest der Server die Client-Nachricht mit der Funktion read() in den Puffer „buf“ und gibt sie dann auf der Konsole aus. Die Funktion send() wird vom Server verwendet, um eine Nachricht als Antwort an den Client zu senden. Schließlich schließt der Server mit close() den Socket des Clients und beendet das Programm, sodass alle Verbindungen ordnungsgemäß geschlossen werden und keine Gefahr einer Datenschutzverletzung besteht.

2. Client-Seite

Sehen wir uns nun an, was im Client-Modell passiert:

#include
#include
#include
#include

#define PORT 8080
#define SERVER_IP „127.0.0.1“

int hauptsächlich ( ) {
int cli_socket ;
Struktur sockaddr_in ser_address ;
const verkohlen * Nachricht = „Kunde sendet Grüße!“ ;

Wenn ( ( cli_socket = Steckdose ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
Fehler ( „Fehler bei der Socket-Erstellung“ ) ;
Ausfahrt ( EXIT_FAILURE ) ;
}

ser_address. sin_family = OF_INET ;
ser_address. sin_port = htons ( HAFEN ) ;

Wenn ( inet_pton ( AF_INET, SERVER_IP, & ser_address. sin_addr ) <= 0 ) {
Fehler ( 'Falsche Adresse' ) ;
Ausfahrt ( EXIT_FAILURE ) ;
}

Wenn ( verbinden ( cli_socket, ( Struktur sockaddr * ) & ser_address, Größe von ( ser_address ) ) == - 1 ) {
Fehler ( 'Verbindungsfehler' ) ;
Ausfahrt ( EXIT_FAILURE ) ;
}
schicken ( cli_socket, mesg, strlen ( Nachricht ) , 0 ) ;

verkohlen buf [ 1024 ] = { 0 } ;
lesen ( cli_socket, buf, Größe von ( buf ) ) ;
std :: cout << „Serverantwort:“ << buf << std :: endl ;

schließen ( cli_socket ) ;
zurückkehren 0 ;
}

Sehen wir uns jede Codezeile an, um zu verstehen, wie das Programm funktioniert.

Die gleichen vier Bibliotheken – iostream, cstring, unistd.h und arpa/inet.h – sind auch auf der Clientseite enthalten. Zusammen mit der IP-Adresse des lokalen Hosts 127.0.0.1 wird auch eine Portnummer definiert. Die Nachricht, die an den Server zugestellt werden muss, wird angegeben. Der Client und der Server müssen im folgenden Schritt eine Verbindung herstellen:

Das „if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1);“ Erstellt einen Socket für IPv4 mit einem Stream-Typ und dem Standardprotokoll TCP. Wenn die Funktion socket() keine Verbindung herstellen kann, gibt perror() die Fehlerdetails aus und beendet das Programm.

Der „server_address.sin_port = htons(PORT);“ Legt die Portnummer nach der Konvertierung in die Netzwerk-Byte-Reihenfolge fest. Anschließend wird hier eine weitere Fehlermeldung ausgegeben, nämlich „Falsche Adresse“, die gedruckt wird, wenn mit der Adresse etwas nicht stimmt. Durch Suchen der Adresse in „ser_address“ stellt der Client eine Verbindung zum Server her. Wenn die Verbindung fehlschlägt, werden die Fehlerdetails gedruckt. Die Funktion send() überträgt die Nachricht an den Server und stellt sicher, dass sie kein Flag enthält.

Um eine Antwort vom Server zu empfangen und zu speichern, wird ein Puffer namens „buf“ vom Typ „char“ initialisiert. Die Funktion read() liest die Antwort des Servers in den Puffer. Abschließend wird die Antwort des Servers auf der Konsole ausgegeben. Abschließend wird die Verbindung mit der close()-Anweisung geschlossen, um den Socket zu beenden. Das Folgende ist die Ausgabe des Programms:

Abschluss

Socket-Programmierung ist ein wichtiger Bestandteil der Netzwerkkommunikation in der Informatik. Es ermöglicht die Entwicklung von Anwendungen, die über das Netzwerk kommunizieren können, und ermöglicht so ein breites Spektrum an Möglichkeiten von einfachen Client-Server-Architekturen bis hin zu strukturierten verteilten Systemen. Wenn ein Socket in einem Programmierkontext erstellt wird, muss das Programm seine Endpunkteigenschaften wie die Protokolle TCP oder UDP und die Netzwerkadresse wie die IP-Adresse und die Portnummer konfigurieren. Über diese Sockets können die Server Daten senden und empfangen. Dieser Artikel zeigt ein praktisches Beispiel für die Funktionsweise des Client-Server-Modells in der Socket-Programmierung.