Програмирање утичнице у Ц

Програмирање утичнице у Ц

Програмирање утичнице је начин повезивања два чвора на мрежи ради међусобног комуницирања. Једна утичница (чвор) слуша на одређеном порту на ИП-у, док друга утичница допире до друге да би успоставила везу. Сервер формира утичницу слушаоца док клијент посеже до сервера.
Програмирање утичнице се широко користи у апликацијама за размену тренутних порука, бинарном стримовању и сарадњи докумената на платформама за стриминг на мрежи итд.

Пример

У овом Ц програму размењујемо једну здраву поруку између сервера и клијента да бисмо демонстрирали модел клијент/сервер.

сервер.ц

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  ;   }   

клијент.ц

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  ;   }   


Састављање

 gcc client.c -o clientgcc server.c -o server  


Излаз

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

Компоненте програмирања соцкета

1. Утичнице

Утичнице су једна од основних компоненти које програм користи за приступ мрежи ради комуникације са другим процесима/чворовима преко мреже. То је једноставно комбинација ИП адресе и броја порта који делује као крајња тачка за комуникацију.
Пример: 192.168.1.1:8080 где два дела одвојена двоточком представљају ИП адреса ( 192.168.1.1 ) анд тхе број порта ( 8080 ).

Типови утичница:

  • ТЦП утичница (Стреам Соцкет): Пружа поуздану комуникацију засновану на вези (тј. ТЦП протокол ).
  • УДП утичница (датаграмска утичница): Омогућава бржу комуникацију без везе, али непоуздану (тј. УДП протокол ).

2. Модел клијент-сервер

Тхе клијент-сервер модел односи се на архитектуру која се користи у програмирању сокета где клијент и сервер међусобно комуницирају ради размене информација или услуга. Ова архитектура омогућава клијенту да шаље захтеве за услугу, а серверу да обрађује и шаље одговоре на те захтеве за услугу.

Дијаграм стања за модел сервера и клијента

Програмирање утичнице у ЦДијаграм стања за серверски и клијентски модел Соцкета

Програмирање утичнице у Ц-у је моћан начин управљања мрежном комуникацијом.

Креирање процеса на страни сервера

Сервер се креира следећим корацима:

1. Креирање утичнице

Овај корак укључује креирање утичнице помоћу функције соцкет().

Параметри:

  • соцкфд: дескриптор утичнице цео број (попут ручице датотеке)
  • домен: цео број специфицира комуникациони домен. Користимо АФ_ ЛОЦАЛ како је дефинисано у ПОСИКС стандарду за комуникацију између процеса на истом хосту. За комуникацију између процеса на различитим хостовима повезаним преко ИПВ4 користимо АФ_ИНЕТ и АФ_И НЕТ 6 за процесе повезане преко ИПВ6.
  • тип: тип комуникације
    СОЦК_СТРЕАМ: ТЦП (оријентисан на поуздану везу)
    СОЦК_ДГРАМ: УДП (непоуздано без везе)
  • протокол: Вредност протокола за Интернет Протоцол(ИП) која је 0. Ово је исти број који се појављује у пољу протокола у ИП заглављу пакета. (ман протоколи за више детаља)
C
   sockfd     =     socket  (  domain       type       protocol  )   

2. Подесите утичницу опт

Ово помаже у манипулисању опцијама за утичницу на коју упућује дескриптор датотеке соцкфд. Ово је потпуно опционо, али помаже у поновној употреби адресе и порта. Спречава грешке као што су: адреса која се већ користи.

C
   setsockopt  (  sockfd       level       optname       optval       socklen_t     optlen  );   

3. Везите

Након креирања утичнице, функција бинд() повезује сокет са адресом и бројем порта наведеним у аддр(прилагођена структура података). У примеру кода везујемо сервер за локални хост, па користимо ИНАДДР_АНИ да наведемо ИП адресу.

C++
   bind  (  sockfd       sockaddr     *  addr       socklen_t     addrlen  );   

Параметри:

  • соцкфд : дескриптор датотеке соцкет креиран помоћу функције соцкет().
  • аддр : показивач на структуру соцкаддр која садржи ИП адресу и број порта за повезивање утичнице.
  • аддрлен : дужина структуре адресе.

4. Слушајте

У овом кораку сервер користи функцију листен() која поставља утичницу сервера у пасивни режим где чека да се клијент приближи серверу да би успоставио везу. Заостатак дефинише максималну дужину до које може да порасте ред веза на чекању за соцкфд. Ако захтев за повезивање стигне када је ред пун, клијент може добити грешку са индикацијом ЕЦОННРЕФУСЕД.

C
   listen  (  sockfd       backlog  );   

Параметерс :

  • соцкфд : дескриптор датотеке соцкет креиран помоћу функције соцкет().
  • заостатак : број који представља величину реда који држи везе на чекању док сервер чека да прихвати везу.

5. Прихватите

У овом кораку сервер издваја први захтев за повезивање из реда веза на чекању за утичницу за слушање, соцкфд креира нову повезану утичницу користећи прихвати() функцију и враћа нови дескриптор датотеке који се односи на ту утичницу. У овом тренутку се успоставља веза између клијента и сервера и они су спремни за пренос података.

C
   new_socket  =     accept  (  sockfd       sockaddr     *  addr       socklen_t     *  addrlen  );   

Параметри:

  • соцкфд : дескриптор датотеке соцкета који враћају соцкет() и бинд().
  • аддр : показивач на структуру соцкаддр која ће садржати ИП адресу клијента и број порта.
  • аддрлен : показивач на променљиву која одређује дужину адресне структуре.

6. Пошаљи/прими

У овом кораку сервер може да шаље или прима податке од клијента.

Пошаљи(): да пошаље податке клијенту

C
   send  (  sockfd       *  buf       len       flags  );   

Параметри:

  • соцкфд : дескриптор датотеке соцкета који враћа функција соцкет().
  • буф : показивач на бафер који садржи податке који се шаљу.
  • само : број бајтова података који се шаљу.
  • заставе : цео број који специфицира различите опције за начин на који се подаци шаљу обично 0 се користи за подразумевано понашање.

Прими() : да добије податке од клијента.

C
   recv  (     sockfd       *  buf       len       flags  );   

Параметри:

  • соцкфд : дескриптор датотеке соцкета који враћа функција соцкет().
  • буф : показивач на бафер који садржи податке за чување.
  • само : број бајтова података који се шаљу.
  • заставе : цео број који специфицира различите опције за начин на који се подаци шаљу обично 0 се користи за подразумевано понашање.

6. Затвори

Након што је размена информација завршена, сервер затвара сокет помоћу функције цлосе() и ослобађа системске ресурсе.

C
   close  (  fd  );   

Параметри:

  • фд: дескриптор датотеке утичнице.

Креирање процеса на страни клијента

Пратите доле наведене кораке за креирање процеса на страни клијента:

1. Прикључак утичнице

Овај корак укључује креирање утичнице која се ради на исти начин као и креирање сокета сервера

2. Повежите се

Системски позив цоннецт() повезује утичницу на коју се позива дескриптор датотеке соцкфд са адресом коју је навео аддр. Адреса и порт сервера су наведени у адр.

C++
   connect  (  sockfd       sockaddr     *  addr       socklen_t     addrlen  );   

Параметерс

  • соцкфд : дескриптор датотеке соцкета који враћа функција соцкет().
  • аддр : показивач на структуру соцкаддр која садржи ИП адресу сервера и број порта.
  • аддрлен : величина адр.

3. Пошаљи/прими

У овом кораку клијент може да шаље или прима податке са сервера, што се ради помоћу функција сенд() и рециеве() слично као што сервер шаље/прима податке од клијента.

4. Затвори

Када се размена информација заврши, клијент такође треба да затвори креирану утичницу и ослободи системске ресурсе користећи цлосе() функцију на исти начин као и сервер.

Уобичајени проблеми и њихови поправци у програмирању сокета

  • Грешке везе: Да бисмо избегли грешке у вези, требало би да обезбедимо да клијент покушава да се повеже са исправним ИП адреса и порт .
  • Грешке при повезивању порта: Ове грешке се јављају када је порт већ у употреби од стране друге апликације у овом сценарију, повезивање за тај порт неће успети. Покушајте да користите други порт или затворите претходну апликацију помоћу порта.
  • Блокирајуће утичнице: Подразумевано, утичнице су блокиране. То значи да ће позиви као што су аццепт() или рецв() чекати бесконачно ако нема клијентске везе или података. Ако је потребно, можете подесити утичницу у режим без блокирања.
Креирај квиз

Топ Чланци

Категорија