Socketprogrammering in C++

Socketprogrammering In C



Socketprogrammering is een belangrijk onderwerp geworden op het gebied van computernetwerken. Het gaat om het tot stand brengen van een verbinding tussen twee knooppunten, server en client om zonder enige onderbreking met elkaar te communiceren. De server fungeert als luisteraar in het communicatiekanaal en luistert naar de client op een specifieke poort op een IP-adres. Aan de andere kant fungeert de cliënt als communicator in het communicatiekanaal. De client neemt contact op met de server om een ​​verbinding tot stand te brengen en contact te maken met de server. Dit artikel is bedoeld om een ​​uitgebreide en gedetailleerde handleiding te bieden voor socketprogrammering in C++, waarin de basisbeginselen worden behandeld, praktische voorbeelden worden gepresenteerd en een gedetailleerde uitleg van de code wordt gegeven.

Het client-servermodel opzetten

Socketprogrammering is het proces dat een communicatiekanaal tussen de server en de client opbouwt met behulp van sockets. In de volgende voorbeeldcode start de client een contact met de server en wordt de server ingesteld om de clientverbindingen te accepteren. Laten we de server- en clientcodesegmenten begrijpen door hun kernwerking binnen de netwerkcommunicatie te demonstreren. Het volgende is de code aan de serverzijde. Laten we eerst de code bekijken en vervolgens de code punt voor punt in detail uitleggen.

1. Serverzijde







De code voor de serverzijde van het model wordt hieronder gegeven. Laten we eens kijken wat er in de code gebeurt:



#include
#include
#include
#include

gebruik makend van naamruimte soa ;

#define POORT 8080
#define MAX_BUF_SIZE 1024

int voornaamst ( ) {
int ser_socket, cli_socket ;
structureren sockaddr_in ser_adres, cli_adres ;
verkoold buf [ MAX_BUF_SIZE ] = { 0 } ;

als ( ( ser_socket = stopcontact ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
fout ( 'Fout bij het maken van Socket' ) ;
Uitgang ( EXIT_FAILURE ) ;
}

ser_adres. zonde_familie = OF_INET ;
ser_adres. sin_adr . s_adres = INADDR_ANY ;
ser_adres. sin_port = htons ( HAVEN ) ;

als ( binden ( be_socket, ( structureren sokkenadr * ) & ser_adres, De grootte van ( ser_adres ) ) == - 1 ) {
fout ( 'Mislukt in binding' ) ;
Uitgang ( EXIT_FAILURE ) ;
}

als ( luisteren ( be_socket, 3 ) == - 1 ) {
fout ( 'Kon niet luisteren' ) ;
Uitgang ( EXIT_FAILURE ) ;
}

uit << 'Server luistert op poort' << HAVEN << '... \N ' ;

socklen_t cli_address_len = De grootte van ( cli_adres ) ;
als ( ( cli_socket = aanvaarden ( be_socket, ( structureren sokkenadr * ) & cli_adres, & cli_adres_len ) ) == - 1 ) {
fout ( 'Kan niet accepteren' ) ;
Uitgang ( EXIT_FAILURE ) ;
}

lezen ( cli_socket, buf, MAX_BUF_SIZE ) ;
uit << 'De boodschap van de klant is:' << buf << eindl ;

versturen ( cli_socket, 'Serverbericht' , strlen ( 'Serverbericht' ) , 0 ) ;

dichtbij ( cli_socket ) ;
dichtbij ( ser_socket ) ;

opbrengst 0 ;
}

Het gegeven voorbeeld is de server-side code van het C++-programma. Deze code werkt voor een eenvoudige TCP-server om te luisteren naar verbindingen op een enkele specifieke poort. Wanneer een verbinding succesvol tot stand is gebracht, ontvangt de server een bericht dat door de client wordt verzonden. Daarna drukt het het af op de console en stuurt het een antwoordbericht naar de client. Laten we elke regel code begrijpen.



Het programma begint met het opnemen van de bibliotheken: “iostream” voor standaard invoer-/uitvoerdefinities, “cstring” voor functies voor het verwerken van tekenreeksen, “unistd.h” om toegang te bieden tot de POSIX-besturingssysteem-API, en “arpa/inet.h” om voer de internetbewerkingen uit. De instructie “#define PORT 8080” betekent dat deze het poortnummer 8080 definieert waarop de server zal luisteren. De “#define MAX_BUF_SIZE 1024” betekent de maximale buffergrootte voor de inkomende gegevens, namelijk 1024.





In de hoofdfunctie worden twee variabelen geïnitialiseerd, “ser_socket” en “cli_socket”, om respectievelijk zowel de server als de client te vertegenwoordigen. De andere drie variabelen, namelijk “sockaddr_in”, “ser_address” en “cli_address” van het type “struct”, worden geïnitialiseerd als adresstructuren voor de server en client. Daarna wordt een buffer met de naam “buf” geïnitialiseerd, waarin de gegevens worden opgeslagen die afkomstig zijn van de client.

De socket()-functie in de “if”-voorwaarde creëert een nieuwe TCP-socket. AF_INET staat voor IPv4, SOCK_STREAM vertegenwoordigt de verbindingsgerichte en betrouwbare TCP-socket, het laatste argument dat 0 is, wordt gegeven om het standaard TCP-protocol te selecteren, INADDR_ANY accepteert de verbindingen op elk IP-adres en htons (PORT) converteert het poortnummer van de bytevolgorde van de host naar de bytevolgorde van het netwerk.



Omdat alles goed is gedefinieerd, is de volgende stap het instellen van de server als een lister op de gegeven poort en het accepteren van de verbindingen op elke netwerkinterface. De socket wordt gegeven met de informatie in “ser_address” door de bind() methode. We drukken een foutmelding af en beëindigen het proces als de binding mislukt. De accept()-functie opent een nieuwe socket voor de verbinding met de client, terwijl de luister()-functie de server instrueert te wachten op inkomende verbindingen. Als de functie accept() mislukt, wordt het foutbericht afgedrukt en wordt de functie afgesloten.

Vervolgens leest de server het clientbericht met de functie read() in de “buf”-buffer en drukt het vervolgens af naar de console. De functie send() wordt door de server gebruikt om een ​​bericht te verzenden als reactie op de client. Ten slotte sluit de server met behulp van close() de socket van de client, waardoor het programma wordt beëindigd, zodat alle verbindingen correct worden gesloten en er geen kans op datalekken bestaat.

2. Klantzijde

Laten we nu eens kijken wat er gebeurt in het klantmodel:

#include
#include
#include
#include

#define POORT 8080
#define SERVER_IP '127.0.0.1'

int voornaamst ( ) {
int cli_socket ;
structureren sockaddr_in ser_adres ;
const verkoold * bericht = 'Klant verzendt groeten!' ;

als ( ( cli_socket = stopcontact ( AF_INET, SOCK_STREAM, 0 ) ) == - 1 ) {
fout ( 'Fout bij het maken van sockets' ) ;
Uitgang ( EXIT_FAILURE ) ;
}

ser_adres. zonde_familie = OF_INET ;
ser_adres. sin_port = htons ( HAVEN ) ;

als ( inet_pton ( AF_INET, SERVER_IP, & ser_adres. sin_adr ) <= 0 ) {
fout ( 'Verkeerde adres' ) ;
Uitgang ( EXIT_FAILURE ) ;
}

als ( aansluiten ( cli_socket, ( structureren sokkenadr * ) & ser_adres, De grootte van ( ser_adres ) ) == - 1 ) {
fout ( 'Verbindingsfout' ) ;
Uitgang ( EXIT_FAILURE ) ;
}
versturen ( cli_socket, bericht, strlen ( bericht ) , 0 ) ;

verkoold buf [ 1024 ] = { 0 } ;
lezen ( cli_socket, buf, De grootte van ( buf ) ) ;
soa :: uit << 'Serverantwoord:' << buf << soa :: eindl ;

dichtbij ( cli_socket ) ;
opbrengst 0 ;
}

Laten we elke regel code bekijken om te begrijpen hoe het programma werkt.

Dezelfde vier bibliotheken – iostream, cstring, unistd.h en arpa/inet.h – zijn ook opgenomen aan de clientzijde. Er wordt ook een poortnummer gedefinieerd samen met het IP-adres van de lokale host 127.0.0.1. Het bericht dat op de server moet worden afgeleverd, wordt gegeven. De client en server moeten als volgt een verbinding tot stand brengen:

De “if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1);” creëert een socket voor IPv4 met een streamtype en het standaardprotocol TCP. De perr() drukt de foutdetails af als de functie socket() er niet in slaagt een verbinding tot stand te brengen en het programma af te sluiten.

De “server_address.sin_port = htons(POORT);” stelt het poortnummer in na conversie naar de bytevolgorde van het netwerk. Daarna wordt hier nog een foutbericht weergegeven, namelijk 'Verkeerd adres', dat wordt afgedrukt als er iets mis is met het adres. Door het adres in het “ser_address” te lokaliseren, zal de client verbinding maken met de server. Als de verbinding mislukt, worden de foutgegevens afgedrukt. De functie send() verzendt het bericht naar de server en zorgt ervoor dat het geen vlag bevat.

Om een ​​antwoord van de server te ontvangen en op te slaan, wordt een buffer met de naam “buf” van het type “char” geïnitialiseerd. De functie read() leest het antwoord van de server in de buffer. Ten slotte wordt het antwoord van de server naar de console afgedrukt. Ten slotte wordt de verbinding gesloten met behulp van de instructie close() om de socket te beëindigen. Het volgende is de uitvoer van het programma:

Conclusie

Socketprogrammering is een belangrijk onderdeel van netwerkcommunicatie in de informatica. Het maakt de ontwikkeling mogelijk van applicaties die via het netwerk kunnen communiceren, waardoor een breed scala aan mogelijkheden mogelijk wordt, van eenvoudige client-server-architecturen tot gestructureerde gedistribueerde systemen. Wanneer een socket wordt gemaakt in een programmeercontext, moet het programma de eindpuntkenmerken ervan configureren, zoals de protocollen, TCP of UDP, en het netwerkadres, zoals het IP-adres en poortnummer. Met deze sockets kunnen de servers de gegevens verzenden en ontvangen. Dit artikel demonstreert een praktisch voorbeeld van hoe het client-server-model bij socketprogrammering werkt.