Socket programmēšana C valodā

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  


Izvade

 Client:Hello message sentHello from serverServer:Hello from clientHello message sent  

Socket 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 programmēšana C valodā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).
C
   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ā.
Izveidojiet viktorīnu