Socket programozás C-ben

Socket programozás C-ben

Socket programozás a hálózat két csomópontjának összekapcsolásának módja, hogy kommunikáljanak egymással. Az egyik socket(csomópont) egy adott IP-porton figyel, míg a másik socket eléri a másikat, hogy kapcsolatot hozzon létre. A kiszolgáló képezi a figyelő socketet, miközben a kliens eléri a szervert.
A socket programozást széles körben használják azonnali üzenetküldő alkalmazásokban, bináris streamingben és dokumentum-együttműködésben online streaming platformokon stb.

Példa

Ebben a C programban egy üdvözlő üzenetet váltunk a szerver és a kliens között, hogy bemutassuk a kliens/szerver modellt.

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

ügyfél.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  ;   }   


Összeállítás

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


Kimenet

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

A Socket programozás összetevői

1. Aljzatok

Aljzatok a program által a hálózat eléréséhez használt alapvető összetevők egyike, hogy a hálózaton keresztül más folyamatokkal/csomópontokkal kommunikálhasson. Ez egyszerűen egy IP-cím és egy portszám kombinációja, amely a kommunikáció végpontjaként működik.
Példa: 192.168.1.1:8080 ahol a kettősponttal elválasztott két rész a IP-cím (192.168.1.1) és a portszám (8080).

Aljzatok típusai:

  • TCP Socket (Stream Socket): Megbízható kapcsolat alapú kommunikációt biztosít (pl. TCP protokoll ).
  • UDP Socket (Datagram Socket): Gyorsabb, de megbízhatatlanabb kapcsolat nélküli kommunikációt biztosít (pl. UDP protokoll ).

2. Kliens-szerver modell

A kliens-szerver modell a socket programozásban használt architektúrára utal, ahol a kliens és a szerver interakcióba lép egymással információ- vagy szolgáltatáscsere céljából. Ez az architektúra lehetővé teszi, hogy az ügyfél szolgáltatáskéréseket küldjön, a szerver pedig feldolgozza és válaszokat küldjön ezekre a szolgáltatáskérésekre.

Állapotdiagram kiszolgáló- és ügyfélmodellhez

Socket programozás C-benÁllapotdiagram a Socket szerver és kliens modelljéhez

A socket programozás C nyelven hatékony módja a hálózati kommunikáció kezelésének.

Szerveroldali folyamat létrehozása

A szerver a következő lépésekkel jön létre:

1. Socket létrehozása

Ez a lépés magában foglalja a socket létrehozását a socket() függvény segítségével.

Paraméterek:

  • sockfd: socket leíró egész szám (például fájlkezelő)
  • domain: integer a kommunikációs tartományt adja meg. Az ugyanazon a gazdagépen lévő folyamatok közötti kommunikációhoz a POSIX szabványban meghatározott AF_LOCAL-t használjuk. Az IPV4 által összekapcsolt különböző gazdagépeken lévő folyamatok közötti kommunikációhoz az AF_INET és az AF_I NET 6 protokollt használjuk az IPV6 által összekapcsolt folyamatokhoz.
  • típus: kommunikációs típus
    SOCK_STREAM: TCP (megbízható kapcsolat-orientált)
    SOCK_DGRAM: UDP (megbízhatatlan kapcsolat nélküli)
  • jegyzőkönyv: Az Internet Protocol(IP) protokollértéke, amely 0. Ez ugyanaz a szám, amely a csomag IP-fejlécében a protokoll mezőben jelenik meg. (a további részletekért a man protokollok)
C
   sockfd     =     socket  (  domain       type       protocol  )   

2. Állítsa be az aljzat opt

Ez segít a sockfd fájlleíró által hivatkozott socket opcióinak manipulálásában. Ez teljesen opcionális, de segít a cím és a port újrafelhasználásában. Megakadályozza az olyan hibákat, mint például: a cím már használatban van.

C
   setsockopt  (  sockfd       level       optname       optval       socklen_t     optlen  );   

3. Köt

A socket létrehozása után a bind() függvény a socketet az addr-ban (egyéni adatstruktúra) megadott címhez és portszámhoz köti. A példakódban a szervert a localhost-hoz kötjük, ezért az INADDR_ANY-t használjuk az IP-cím megadására.

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

Paraméterek:

  • sockfd : a socket() függvény segítségével létrehozott socket fájlleíró.
  • cím : mutató a sockaddr struct-ra, amely tartalmazza a socket összekapcsolásához szükséges IP-címet és portszámot.
  • addrlen : az addr szerkezet hossza.

4. Figyelj

Ebben a lépésben a kiszolgáló a listen() függvényt használja, amely passzív módba helyezi a szerver socketet, ahol megvárja, amíg a kliens megkeresi a szervert, hogy kapcsolatot létesítsen. A hátralék határozza meg azt a maximális hosszt, ameddig a sockfd függőben lévő kapcsolatok sora növekedhet. Ha a csatlakozási kérelem akkor érkezik, amikor a sor megtelt, az ügyfél hibaüzenetet kaphat az ECONNREFUSED jelzéssel.

C
   listen  (  sockfd       backlog  );   

Paraméterek :

  • sockfd : a socket() függvény segítségével létrehozott socket fájlleíró.
  • hátralék : szám, amely a függőben lévő kapcsolatokat tároló sor méretét jelzi, miközben a szerver a kapcsolat elfogadására vár.

5. Elfogadás

Ebben a lépésben a szerver kibontja az első csatlakozási kérelmet a függőben lévő kapcsolatok sorából a hallgatási sockethez. A sockfd új csatlakoztatott socketet hoz létre a elfogad () függvényt, és egy új fájlleírót ad vissza az adott socketre hivatkozva. Ekkor létrejön a kapcsolat a kliens és a szerver között, és készen állnak az adatátvitelre.

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

Paraméterek:

  • sockfd : a socket fájlleírót a socket() és a bind() adja vissza.
  • cím : mutat egy struct sockaddr-re, amely az ügyfél IP-címét és portszámát fogja tárolni.
  • addrlen : mutató a címstruktúra hosszát meghatározó változóra.

6. Küldés/fogadás

Ebben a lépésben a szerver adatokat küldhet vagy fogadhat a klienstől.

Elküld(): adatokat küldeni az ügyfélnek

C
   send  (  sockfd       *  buf       len       flags  );   

Paraméterek:

  • sockfd : a socket() függvény által visszaadott socket fájlleíró.
  • buf : mutató a küldendő adatokat tartalmazó pufferre.
  • csak : az elküldendő adatok bájtjainak száma.
  • zászlókat : egész szám, amely különféle beállításokat ad meg az adatok küldésének módjára vonatkozóan, általában a 0 az alapértelmezett viselkedés.

Fogadás() : hogy megkapja az adatokat az ügyféltől.

C
   recv  (     sockfd       *  buf       len       flags  );   

Paraméterek:

  • sockfd : a socket() függvény által visszaadott socket fájlleíró.
  • buf : mutató a tárolandó adatokat tartalmazó pufferre.
  • csak : az elküldendő adatok bájtjainak száma.
  • zászlókat : egész szám, amely különféle beállításokat ad meg az adatok küldésének módjára vonatkozóan, általában a 0 az alapértelmezett viselkedés.

6. Zárja be

Az információcsere befejezése után a szerver a close() függvény segítségével bezárja a socketet, és felszabadítja a rendszererőforrásokat.

C
   close  (  fd  );   

Paraméterek:

  • fd: a socket fájlleírója.

Ügyféloldali folyamat létrehozása

Kövesse az alábbi lépéseket az ügyféloldali folyamat létrehozásához:

1. Aljzatcsatlakozás

Ez a lépés magában foglalja a socket létrehozását, amely ugyanúgy történik, mint a szerver socket létrehozása

2. Csatlakozás

A connect() rendszerhívás a sockfd fájlleíró által hivatkozott socketet az addr által megadott címhez köti. A szerver címe és portja a címben van megadva.

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

Paraméterek

  • sockfd : a socket() függvény által visszaadott socket fájlleíró.
  • cím : mutató a struct sockaddr-hez, amely tartalmazza a szerver IP-címét és portszámát.
  • addrlen : a cím mérete.

3. Küldés/fogadás

Ebben a lépésben a kliens adatokat küldhet vagy fogadhat a szerverről, ami a send() és recive() függvényekkel történik, hasonlóan ahhoz, ahogyan a szerver adatokat küld/fogad a klienstől.

4. Zárja be

Az információcsere befejezése után a kliensnek be kell zárnia a létrehozott socketet, és fel kell szabadítania a rendszererőforrásokat a close() függvény használatával, ugyanúgy, mint a szerver.

Gyakori problémák és megoldásaik a socket programozásban

  • Csatlakozási hibák: A csatlakozási hibák elkerülése érdekében meg kell győződnünk arról, hogy a kliens a megfelelő hálózathoz próbál csatlakozni IP cím és port .
  • Portkötési hibák: Ezek a hibák akkor fordulnak elő, ha egy portot egy másik alkalmazás már használ ebben a forgatókönyvben az adott porthoz való kötődés meghiúsul. Próbáljon meg másik portot használni, vagy zárja be az előző alkalmazást a port használatával.
  • Blokkoló aljzatok: Alapértelmezés szerint az aljzatok blokkolva vannak. Ez azt jelenti, hogy az olyan hívások, mint az accept() vagy recv(), határozatlan ideig várnak, ha nincs ügyfélkapcsolat vagy adat. Szükség esetén az aljzatot nem blokkoló módba állíthatja.
Kvíz létrehozása