Socket programmēšana C valodā
Socket programmēšana ir veids, kā savienot divus tīkla mezglus, lai sazinātos viens ar otru. Viena ligzda (mezgls) klausās noteiktā IP portā, bet otra ligzda sasniedz otru, lai izveidotu savienojumu. Serveris veido klausītāja ligzdu, kamēr klients sasniedz serveri.
Socket programmēšana tiek plaši izmantota tūlītējās ziņojumapmaiņas lietojumprogrammās, binārās straumēšanas un dokumentu sadarbības tiešsaistes straumēšanas platformās utt.
Piemērs
Šajā C programmā mēs apmaināmies ar vienu sveicienu starp serveri un klientu, lai parādītu klienta/servera modeli.
serveris.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 ; }
klients.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 ; }
Sastādīšana
gcc client.c -o clientgcc server.c -o server
IzvadeClient:Hello message sentHello from serverServer:Hello from clientHello message sentSocket programmēšanas sastāvdaļas
1. Kontaktligzdas
Kontaktligzdas ir viens no galvenajiem komponentiem, ko programma izmanto, lai piekļūtu tīklam, lai tīklā sazinātos ar citiem procesiem/mezgliem. Tā ir vienkārši IP adreses un porta numura kombinācija, kas darbojas kā komunikācijas galapunkts.
Piemērs: 192.168.1.1:8080 kur abas ar kolu atdalītās daļas apzīmē IP adrese (192.168.1.1) un porta numurs (8080).Kontaktligzdu veidi:
- TCP ligzda (straumes ligzda): Nodrošina uzticamu uz savienojumu balstītu saziņu (t.i. TCP protokols ).
- UDP ligzda (Datagram Socket): Nodrošina ātrāku, bet neuzticamu saziņu bez savienojuma (t. UDP protokols ).
2. Klienta-servera modelis
The klienta-servera modelis attiecas uz arhitektūru, ko izmanto ligzdas programmēšanai, kur klients un serveris mijiedarbojas viens ar otru, lai apmainītos ar informāciju vai pakalpojumiem. Šī arhitektūra ļauj klientam nosūtīt pakalpojumu pieprasījumus un serverim apstrādāt un nosūtīt atbildes uz šiem pakalpojumu pieprasījumiem.
Stāvokļa diagramma servera un klienta modelim
Socket servera un klienta modeļa stāvokļa diagramma Socket programmēšana C valodā ir spēcīgs veids, kā pārvaldīt tīkla saziņu.
Servera puses procesa izveide
Serveris tiek izveidots, veicot šādas darbības:
1. Socket izveide
Šis solis ietver ligzdas izveidi, izmantojot socket() funkciju.
Parametri:
- sockfd: ligzdas deskriptors vesels skaitlis (piemēram, faila rokturis)
- domēns: vesels skaitlis norāda saziņas domēnu. Mēs izmantojam AF_ LOCAL, kā noteikts POSIX standartā, lai sazinātos starp procesiem vienā un tajā pašā resursdatorā. Saziņai starp procesiem dažādos resursdatoros, kas savienoti ar IPV4, mēs izmantojam AF_INET un AF_I NET 6 procesiem, kas savienoti ar IPV6.
- veids: komunikācijas veids
SOCK_STREAM: TCP (uz uzticamu savienojumu orientēts)
SOCK_DGRAM: UDP (neuzticams bez savienojuma) - protokols: Interneta protokola (IP) protokola vērtība, kas ir 0. Šis ir tas pats skaitlis, kas tiek rādīts protokola laukā paketes IP galvenē (sīkāku informāciju skatiet man protokolos).
sockfd = socket ( domain type protocol )
2. Iestatiet kontaktligzdas op
Tas palīdz manipulēt ar faila deskriptora sockfd norādītās ligzdas opcijām. Tas ir pilnīgi neobligāts, taču tas palīdz atkārtoti izmantot adresi un portu. Novērš tādas kļūdas kā: adrese jau tiek izmantota.
C setsockopt ( sockfd level optname optval socklen_t optlen );
3. Sasiet
Pēc ligzdas izveides funkcija bind() saista ligzdu ar adresi un porta numuru, kas norādīts addr (pielāgota datu struktūra). Piemēra kodā mēs saistām serveri ar vietējo resursdatoru, tāpēc mēs izmantojam INADDR_ANY, lai norādītu IP adresi.
C++ bind ( sockfd sockaddr * addr socklen_t addrlen );
Parametri:
- sockfd : ligzdas faila deskriptors, kas izveidots, izmantojot socket() funkciju.
- adr : rādītājs uz struct sockaddr, kas satur IP adresi un porta numuru ligzdas saistīšanai.
- addrlen : addr struktūras garums.
4. Klausieties
Šajā solī serveris izmanto funkciju listen (), kas ievieto servera ligzdu pasīvā režīmā, kur tas gaida, līdz klients tuvojas serverim, lai izveidotu savienojumu. Neatpaliktais uzkrājums nosaka maksimālo garumu, līdz kuram var pieaugt sockfd neapstiprināto savienojumu rinda. Ja savienojuma pieprasījums tiek saņemts, kad rinda ir pilna, klients var saņemt kļūdu ar norādi ECONNREFUSED.
C listen ( sockfd backlog );
Parametri :
- sockfd : ligzdas faila deskriptors, kas izveidots, izmantojot socket() funkciju.
- atpalicība : skaitlis, kas apzīmē rindas lielumu, kurā atrodas neapstiprinātie savienojumi, kamēr serveris gaida savienojuma pieņemšanu.
5. Pieņemt
Šajā solī serveris izvelk pirmo savienojuma pieprasījumu no gaidošo savienojumu rindas klausīšanās ligzdai sockfd izveido jaunu savienotu ligzdu, izmantojot pieņemt () funkciju un atgriež jaunu faila deskriptoru, kas attiecas uz šo ligzdu. Šajā brīdī tiek izveidots savienojums starp klientu un serveri, un tie ir gatavi datu pārsūtīšanai.
C new_socket = accept ( sockfd sockaddr * addr socklen_t * addrlen );
Parametri:
- sockfd : ligzdas faila deskriptors, ko atgriež socket() un bind().
- adr : rādītājs uz struct sockaddr, kurā būs klienta IP adrese un porta numurs.
- addrlen : rādītājs uz mainīgo, kas norāda adreses struktūras garumu.
6. Nosūtīt/saņemt
Šajā solī serveris var nosūtīt vai saņemt datus no klienta.
Sūtīt (): lai nosūtītu datus klientam
C send ( sockfd * buf len flags );
Parametri:
- sockfd : ligzdas faila deskriptors, ko atgriež funkcija socket().
- buf : rādītājs uz buferi, kurā ir nosūtāmie dati.
- tikai : nosūtāmo datu baitu skaits.
- karogi : vesels skaitlis, kas norāda dažādas datu nosūtīšanas iespējas, parasti noklusējuma darbībai tiek izmantots 0.
Saņemt() : lai saņemtu datus no klienta.
C recv ( sockfd * buf len flags );
Parametri:
- sockfd : ligzdas faila deskriptors, ko atgriež funkcija socket().
- buf : rādītājs uz buferi, kurā ir saglabājamie dati.
- tikai : nosūtāmo datu baitu skaits.
- karogi : vesels skaitlis, kas norāda dažādas datu nosūtīšanas iespējas, parasti noklusējuma darbībai tiek izmantots 0.
6. Aizveriet
Kad informācijas apmaiņa ir pabeigta, serveris aizver ligzdu, izmantojot funkciju close() un atbrīvo sistēmas resursus.
C close ( fd );
Parametri:
- fd: ligzdas faila deskriptors.
Klienta puses procesa izveide
Lai izveidotu klienta puses procesu, veiciet tālāk norādītās darbības.
1. Kontaktligzdas savienojums
Šis solis ietver ligzdas izveidi, kas tiek veikta tāpat kā servera ligzdas izveide
2. Savienot
Sistēmas izsaukums connect() savieno ligzdu, uz kuru atsaucas faila deskriptors sockfd, ar adresi, kas norādīta adr. Servera adrese un ports ir norādīts adr.
C++ connect ( sockfd sockaddr * addr socklen_t addrlen );
Parametri
- sockfd : ligzdas faila deskriptors, ko atgriež funkcija socket().
- adr : rādītājs struct sockaddr, kas satur servera IP adresi un porta numuru.
- addrlen : adr.
3. Nosūtīt/saņemt
Šajā solī klients var nosūtīt vai saņemt datus no servera, kas tiek darīts, izmantojot send() un recive() funkcijas līdzīgi kā serveris sūta/saņem datus no klienta.
4. Aizveriet
Kad informācijas apmaiņa ir pabeigta, klientam ir arī jāaizver izveidotā ligzda un jāatbrīvo sistēmas resursi, izmantojot funkciju close() tāpat kā serveris.
Bieži sastopamās problēmas un to labojumi ligzdu programmēšanā
- Savienojuma kļūmes: Lai izvairītos no savienojuma kļūmēm, mums jāpārliecinās, ka klients mēģina izveidot savienojumu ar pareizo IP adrese un ports .
- Portu saistīšanas kļūdas: Šīs kļūdas rodas, ja portu jau izmanto cita lietojumprogramma. Šajā scenārijā saistīšana ar šo portu neizdosies. Mēģiniet izmantot citu portu vai aizveriet iepriekšējo lietojumprogrammu, izmantojot portu.
- Bloķēšanas ligzdas: Pēc noklusējuma ligzdas tiek bloķētas. Tas nozīmē, ka zvani, piemēram, accept() vai recv(), gaidīs bezgalīgi, ja nebūs klienta savienojuma vai datu. Ja nepieciešams, varat iestatīt ligzdu nebloķēšanas režīmā.