Sokkelprogrammering i C
Socket programmering er en måde at forbinde to noder på et netværk for at kommunikere med hinanden. Den ene socket(node) lytter på en bestemt port på en IP, mens den anden socket når ud til den anden for at danne en forbindelse. Serveren danner lytter-socket, mens klienten når ud til serveren.
Socket-programmering er meget udbredt i instant messaging-applikationer binær streaming og dokumentsamarbejde online streaming platforme osv.
Eksempel
I dette C-program udveksler vi en hej-besked mellem server og klient for at demonstrere klient/server-modellen.
server.c
C #include #include #include #include #include #include #define PORT 8080 int main ( int argc char const * argv []) { int server_fd new_socket ; ssize_t valread ; struct sockaddr_in address ; int opt = 1 ; socklen_t addrlen = sizeof ( address ); char buffer [ 1024 ] = { 0 }; char * hello = 'Hello from server' ; // Creating socket file descriptor if (( server_fd = socket ( AF_INET SOCK_STREAM 0 )) < 0 ) { perror ( 'socket failed' ); exit ( EXIT_FAILURE ); } // Forcefully attaching socket to the port 8080 if ( setsockopt ( server_fd SOL_SOCKET SO_REUSEADDR | SO_REUSEPORT & opt sizeof ( opt ))) { perror ( 'setsockopt' ); exit ( EXIT_FAILURE ); } address . sin_family = AF_INET ; address . sin_addr . s_addr = INADDR_ANY ; address . sin_port = htons ( PORT ); // Forcefully attaching socket to the port 8080 if ( bind ( server_fd ( struct sockaddr * ) & address sizeof ( address )) < 0 ) { perror ( 'bind failed' ); exit ( EXIT_FAILURE ); } if ( listen ( server_fd 3 ) < 0 ) { perror ( 'listen' ); exit ( EXIT_FAILURE ); } if (( new_socket = accept ( server_fd ( struct sockaddr * ) & address & addrlen )) < 0 ) { perror ( 'accept' ); exit ( EXIT_FAILURE ); } // subtract 1 for the null // terminator at the end valread = read ( new_socket buffer 1024 - 1 ); printf ( '%s n ' buffer ); send ( new_socket hello strlen ( hello ) 0 ); printf ( 'Hello message sent n ' ); // closing the connected socket close ( new_socket ); // closing the listening socket close ( server_fd ); return 0 ; }
klient.c
C #include #include #include #include #include #define PORT 8080 int main ( int argc char const * argv []) { int status valread client_fd ; struct sockaddr_in serv_addr ; char * hello = 'Hello from client' ; char buffer [ 1024 ] = { 0 }; if (( client_fd = socket ( AF_INET SOCK_STREAM 0 )) < 0 ) { printf ( ' n Socket creation error n ' ); return -1 ; } serv_addr . sin_family = AF_INET ; serv_addr . sin_port = htons ( PORT ); // Convert IPv4 and IPv6 addresses from text to binary // form if ( inet_pton ( AF_INET '127.0.0.1' & serv_addr . sin_addr ) <= 0 ) { printf ( ' n Invalid address/ Address not supported n ' ); return -1 ; } if (( status = connect ( client_fd ( struct sockaddr * ) & serv_addr sizeof ( serv_addr ))) < 0 ) { printf ( ' n Connection Failed n ' ); return -1 ; } // subtract 1 for the null // terminator at the end send ( client_fd hello strlen ( hello ) 0 ); printf ( 'Hello message sent n ' ); valread = read ( client_fd buffer 1024 - 1 ); printf ( '%s n ' buffer ); // closing the connected socket close ( client_fd ); return 0 ; }
Kompilering
gcc client.c -o clientgcc server.c -o server
ProduktionClient:Hello message sentHello from serverServer:Hello from clientHello message sentKomponenter i Socket-programmering
1. Stikkontakter
Stikkontakter er en af kernekomponenterne, der bruges af programmet til at få adgang til netværket for at kommunikere med andre processer/knudepunkter over netværket. Det er simpelthen en kombination af en IP-adresse og et portnummer, der fungerer som et slutpunkt for kommunikation.
Eksempel: 192.168.1.1:8080 hvor de to dele adskilt af kolon repræsenterer IP-adresse (192.168.1.1) og den portnummer (8080).Sokkeltyper:
- TCP Socket (Stream Socket): Giver pålidelig forbindelsesbaseret kommunikation (dvs. TCP protokol ).
- UDP Socket (Datagram Socket): Giver forbindelsesfri kommunikation hurtigere, men upålidelig (dvs. UDP protokol ).
2. Klient-servermodel
De klient-server model refererer til den arkitektur, der bruges i socket-programmering, hvor en klient og en server interagerer med hinanden for at udveksle information eller tjenester. Denne arkitektur giver klienten mulighed for at sende serviceanmodninger og serveren til at behandle og sende svar på disse serviceanmodninger.
Statusdiagram for server- og klientmodel
Statusdiagram for server- og klientmodel af Socket Socket-programmering i C er en effektiv måde at håndtere netværkskommunikation på.
Oprettelse af en proces på serversiden
Serveren oprettes ved hjælp af følgende trin:
1. Socket Oprettelse
Dette trin involverer oprettelsen af socket ved hjælp af socket()-funktionen.
Parametre:
- sockfd: socket descriptor et heltal (som et filhåndtag)
- domæne: heltal angiver kommunikationsdomæne. Vi bruger AF_ LOCAL som defineret i POSIX-standarden til kommunikation mellem processer på samme vært. Til kommunikation mellem processer på forskellige værter forbundet med IPV4 bruger vi AF_INET og AF_I NET 6 til processer forbundet med IPV6.
- type: kommunikationstype
SOCK_STREAM: TCP (pålidelig forbindelsesorienteret)
SOCK_DGRAM: UDP (upålidelig forbindelsesløs) - protokol: Protokolværdi for Internet Protocol(IP), som er 0. Dette er det samme tal, som vises i protokolfeltet i IP-headeren på en pakke.(man-protokoller for flere detaljer)
sockfd = socket ( domain type protocol )
2. Indstil socket opt
Dette hjælper med at manipulere muligheder for socket, der henvises til af filbeskrivelsen sockfd. Dette er helt valgfrit, men det hjælper med genbrug af adresse og port. Forhindrer fejl som: adresse allerede i brug.
C setsockopt ( sockfd level optname optval socklen_t optlen );
3. Bind
Efter oprettelsen af socket binder bind()-funktionen socket til den adresse og portnummer, der er angivet i addr(brugerdefineret datastruktur). I eksempelkoden binder vi serveren til den lokale vært, derfor bruger vi INADDR_ANY til at angive IP-adressen.
C++ bind ( sockfd sockaddr * addr socklen_t addrlen );
Parametre:
- sockfd : socket-filbeskrivelse oprettet ved hjælp af socket()-funktionen.
- adr : peger på en struct sockaddr, der indeholder IP-adressen og portnummeret til at binde soklen.
- addrlen : længden af addr-strukturen.
4. Lyt
I dette trin bruger serveren listen()-funktionen, der sætter serversocket i en passiv tilstand, hvor den venter på, at klienten nærmer sig serveren for at oprette forbindelse. Efterslæbet definerer den maksimale længde, som køen af afventende forbindelser til sockfd kan vokse til. Hvis en forbindelsesanmodning ankommer, når køen er fuld, kan klienten modtage en fejl med en indikation af ECONNREFUSED.
C listen ( sockfd backlog );
Parametre :
- sockfd : socket-filbeskrivelse oprettet ved hjælp af socket()-funktionen.
- efterslæb : tal, der repræsenterer størrelsen af køen, der holder de afventende forbindelser, mens serveren venter på at acceptere en forbindelse.
5. Accepter
I dette trin udtrækker serveren den første forbindelsesanmodning fra køen af afventende forbindelser til lyttesocket sockfd opretter en ny tilsluttet socket ved hjælp af acceptere() funktion og returnerer en ny filbeskrivelse, der henviser til den socket. På dette tidspunkt er forbindelsen etableret mellem klient og server, og de er klar til at overføre data.
C new_socket = accept ( sockfd sockaddr * addr socklen_t * addrlen );
Parametre:
- sockfd : socket-filbeskrivelse returneret af socket() og bind().
- adr : peger på en struct sockaddr, der skal indeholde klientens IP-adresse og portnummer.
- addrlen : pointer til en variabel, der angiver længden af adressestrukturen.
6. Send/modtag
I dette trin kan serveren sende eller modtage data fra klienten.
Sende(): at sende data til klienten
C send ( sockfd * buf len flags );
Parametre:
- sockfd : socket-filbeskrivelse returneret af socket()-funktionen.
- buf : peger på bufferen, der indeholder de data, der skal sendes.
- kun : antal bytes data, der skal sendes.
- flag : heltal, der angiver forskellige muligheder for, hvordan dataene sendes, bruges typisk 0 til standardadfærd.
Modtag(): at modtage data fra klienten.
C recv ( sockfd * buf len flags );
Parametre:
- sockfd : socket-filbeskrivelse returneret af socket()-funktionen.
- buf : markør til bufferen, der indeholder de data, der skal lagres.
- kun : antal bytes data, der skal sendes.
- flag : heltal, der angiver forskellige muligheder for, hvordan dataene sendes, bruges typisk 0 til standardadfærd.
6. Luk
Efter at udvekslingen af information er afsluttet, lukker serveren socket ved hjælp af close()-funktionen og frigiver systemressourcerne.
C close ( fd );
Parametre:
- fd: filbeskrivelse af socket.
Oprettelse af proces på klientsiden
Følg nedenstående trin for at oprette en proces på klientsiden:
1. Stikkontakt
Dette trin involverer oprettelsen af socket, hvilket sker på samme måde som serverens socket-oprettelse
2. Tilslut
Connect()-systemkaldet forbinder den socket, der henvises til af filbeskrivelsen sockfd, til den adresse, der er angivet af addr. Serverens adresse og port er angivet i adr.
C++ connect ( sockfd sockaddr * addr socklen_t addrlen );
Parametre
- sockfd : socket-filbeskrivelse returneret af socket()-funktionen.
- adr : pointer til struct sockaddr, der indeholder serverens IP-adresse og portnummer.
- addrlen : størrelse på addr.
3. Send/modtag
I dette trin kan klienten sende eller modtage data fra serveren, hvilket gøres ved hjælp af funktionerne send() og recieve() svarende til hvordan serveren sender/modtager data fra klienten.
4. Luk
Når udvekslingen af information er afsluttet, skal klienten også lukke den oprettede socket og frigive systemressourcerne ved hjælp af close()-funktionen på samme måde som serveren gør.
Almindelige problemer og deres rettelser i socket-programmering
- Forbindelsesfejl: For at undgå forbindelsesfejl bør vi sikre, at klienten forsøger at oprette forbindelse til den rigtige IP-adresse og port .
- Portbindingsfejl: Disse fejl opstår, når en port allerede er i brug af et andet program i dette scenarie, vil bindingen til den port mislykkes. Prøv at bruge en anden port, eller luk det forrige program ved hjælp af porten.
- Blokering af stikkontakter: Som standard blokerer stikkontakter. Det betyder, at opkald som accept() eller recv() vil vente på ubestemt tid, hvis der ikke er nogen klientforbindelse eller data. Du kan indstille stikket til ikke-blokerende tilstand, hvis det er nødvendigt.