logo

Socket-ohjelmointi C-kielellä

Socket-ohjelmointi on tapa yhdistää kaksi solmua verkossa kommunikoidakseen keskenään. Yksi socket (solmu) kuuntelee tiettyä porttia IP-osoitteessa, kun taas toinen pistoke tavoittaa toista yhteyden muodostamiseksi. Palvelin muodostaa kuuntelijan, kun asiakas tavoittaa palvelimen.
Socket-ohjelmointia käytetään laajasti pikaviestintäsovelluksissa, binäärisuoratoistossa ja dokumenttien yhteiskäytössä online-suoratoistoalustoissa jne.

Esimerkki

Tässä C-ohjelmassa vaihdamme yhden tervehdysviestin palvelimen ja asiakkaan välillä näyttääksemme asiakas/palvelin-mallin.

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('%sn' buffer);  send(new_socket hello strlen(hello) 0);  printf('Hello message sentn');  // closing the connected socket  close(new_socket);    // closing the listening socket  close(server_fd);  return 0; } 

asiakas.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(  'nInvalid address/ Address not supported n');  return -1;  }  if ((status  = connect(client_fd (struct sockaddr*)&serv_addr  sizeof(serv_addr)))  < 0) {  printf('nConnection Failed n');  return -1;  }    // subtract 1 for the null  // terminator at the end  send(client_fd hello strlen(hello) 0);  printf('Hello message sentn');  valread = read(client_fd buffer  1024 - 1);   printf('%sn' buffer);  // closing the connected socket  close(client_fd);  return 0; } 


Kokoaminen



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


Lähtö

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

Socket-ohjelmoinnin komponentit

1. Pistorasiat

Pistorasiat ovat yksi ydinkomponenteista, joita ohjelma käyttää verkkoon pääsyyn kommunikoidakseen muiden prosessien/solmujen kanssa verkon kautta. Se on yksinkertaisesti yhdistelmä IP-osoitetta ja porttinumeroa, joka toimii viestinnän päätepisteenä.
Esimerkki: 192.168.1.1:8080 jossa kaksi kaksoispisteellä erotettua osaa edustavat IP-osoite (192.168.1.1) ja portin numero (8080).

Pistorasiatyypit:

  • TCP Socket (Stream Socket): Tarjoaa luotettavan yhteyspohjaisen viestinnän (esim. TCP-protokolla ).
  • UDP Socket (Datagram Socket): Tarjoaa yhteydettömän viestinnän nopeampaa, mutta epäluotettavaa (esim. UDP-protokolla ).

2. Asiakas-palvelinmalli

The asiakas-palvelin malli viittaa arkkitehtuuriin, jota käytetään socket-ohjelmoinnissa, jossa asiakas ja palvelin ovat vuorovaikutuksessa keskenään tietojen tai palvelujen vaihtamiseksi. Tämän arkkitehtuurin avulla asiakas voi lähettää palvelupyyntöjä ja palvelin käsitellä ja lähettää vastaukset näihin palvelupyyntöihin.

Tilakaavio palvelin- ja asiakasmallille

Socket-ohjelmointi C-kielelläTilakaavio Socketin palvelin- ja asiakasmallille

Socket-ohjelmointi C:ssä on tehokas tapa käsitellä verkkoviestintää.

Palvelinpuolen prosessin luominen

Palvelin luodaan seuraavilla vaiheilla:

verilog-parametri

1. Socketin luominen

Tämä vaihe sisältää socketin luomisen käyttämällä socket()-funktiota.

Parametrit:

  • sockfd: socket-kuvaaja kokonaisluku (kuten tiedostokahva)
  • verkkotunnus: kokonaisluku määrittää viestintäalueen. Käytämme POSIX-standardissa määriteltyä AF_LOCAL-arvoa viestintään samassa isäntäkoneessa olevien prosessien välillä. Käytämme AF_INET:tä ja AF_I NET 6:ta IPV6:n yhdistämille prosesseille kommunikointiin eri isännillä olevien prosessien välillä.
  • tyyppi: viestintätyyppi
    SOCK_STREAM: TCP (luotettava yhteyssuuntautunut)
    SOCK_DGRAM: UDP (epäluotettava yhteydetön)
  • protokolla: Internet Protocol(IP) -protokollan arvo, joka on 0. Tämä on sama numero, joka näkyy protokollakentässä paketin IP-otsikossa. (Man-protokollat ​​saadaksesi lisätietoja)
C
sockfd = socket(domain type protocol) 

2. Aseta pistorasia opt

Tämä auttaa käsittelemään tiedostokuvaajan sockfd viittaaman socketin vaihtoehtoja. Tämä on täysin valinnainen, mutta se auttaa osoitteen ja portin uudelleenkäytössä. Estää virheitä, kuten: osoite jo käytössä.

C
setsockopt(sockfd level optname optval socklen_t optlen); 

3. Sido

Socketin luomisen jälkeen bind()-funktio sitoo socketin osoitteeseen ja porttinumeroon, jotka on määritetty addr (mukautettu tietorakenne) -kohdassa. Esimerkkikoodissa sitomme palvelimen localhost-palvelimeen, joten käytämme INADDR_ANY-koodia IP-osoitteen määrittämiseen.

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

Parametrit:

  • sockfd : socket-tiedoston kuvaaja, joka on luotu socket()-funktiolla.
  • osoite : osoitin struct sockaddr, joka sisältää IP-osoitteen ja portin numeron pistokkeen sitomiseksi.
  • addrlen : addr-rakenteen pituus.

4. Kuuntele

Tässä vaiheessa palvelin käyttää listen()-funktiota, joka asettaa palvelinsocketin passiiviseen tilaan, jossa se odottaa asiakkaan lähestyvän palvelinta yhteyden muodostamiseksi. Ruuhka määrittelee enimmäispituuden, johon sockfd:n odottavien yhteyksien jono voi kasvaa. Jos yhteyspyyntö saapuu, kun jono on täynnä, asiakas voi saada virheilmoituksen, jossa lukee ECONNREFUSED.

C
listen(sockfd backlog); 

Parametrit :

  • sockfd : socket-tiedoston kuvaaja, joka on luotu socket()-funktiolla.
  • ruuhkaa : numero, joka edustaa odottavia yhteyksiä sisältävän jonon kokoa, kun palvelin odottaa yhteyden hyväksymistä.

5. Hyväksy

Tässä vaiheessa palvelin poimii ensimmäisen yhteyspyynnön kuunteluliittimen odottavien yhteyksien jonosta sockfd luo uuden yhdistetyn pistorasian käyttämällä hyväksyä() funktion ja palauttaa uuden tiedostokuvaajan, joka viittaa kyseiseen kantaan. Tässä vaiheessa yhteys asiakkaan ja palvelimen välille muodostuu ja ne ovat valmiita siirtämään tietoja.

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

Parametrit:

  • sockfd : socket-tiedoston kuvaaja, jonka socket() ja bind() palauttavat.
  • osoite : osoitin struct sockaddr, joka sisältää asiakkaan IP-osoitteen ja portin numeron.
  • addrlen : osoitin muuttujaan, joka määrittää osoiterakenteen pituuden.

6. Lähetä/vastaanota

Tässä vaiheessa palvelin voi lähettää tai vastaanottaa tietoja asiakkaalta.

Lähetä (): lähettää tietoja asiakkaalle

C
send(sockfd *buf len flags); 

Parametrit:

  • sockfd : socket-tiedoston kuvaaja, jonka socket()-funktio palauttaa.
  • buf : osoitin puskuriin, joka sisältää lähetettävät tiedot.
  • vain : lähetettävän datan tavujen määrä.
  • liput : kokonaisluku, joka määrittää eri vaihtoehdot tietojen lähettämiselle. Yleensä 0:ta käytetään oletuskäyttäytymiseen.

Vastaanota() : saada tiedot asiakkaalta.

C
recv( sockfd *buf len flags); 

Parametrit:

  • sockfd : socket-tiedoston kuvaaja, jonka socket()-funktio palauttaa.
  • buf : osoitin puskuriin, joka sisältää tallennettavat tiedot.
  • vain : lähetettävän datan tavujen määrä.
  • liput : kokonaisluku, joka määrittää eri vaihtoehdot tietojen lähettämiselle. Yleensä 0:ta käytetään oletuskäyttäytymiseen.

6. Sulje

Kun tiedonvaihto on valmis, palvelin sulkee socketin käyttämällä close()-funktiota ja vapauttaa järjestelmäresurssit.

C
close(fd); 

Parametrit:

  • fd: socketin tiedostokuvaus.

Asiakaspuolen prosessin luominen

Luo asiakaspuolen prosessi noudattamalla seuraavia ohjeita:

1. Pistorasialiitäntä

Tämä vaihe sisältää socketin luomisen, joka tehdään samalla tavalla kuin palvelimen socketin luominen

2. Yhdistä

Connect()-järjestelmäkutsu yhdistää tiedostokuvaajan sockfd viittaaman socketin addr:n määräämään osoitteeseen. Palvelimen osoite ja portti on määritetty osoitteessa.

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

Parametrit

  • sockfd : socket-tiedoston kuvaaja, jonka socket()-funktio palauttaa.
  • osoite : osoitin struct sockaddr, joka sisältää palvelimen IP-osoitteen ja portin numeron.
  • addrlen : osoitteen koko

3. Lähetä/vastaanota

Tässä vaiheessa asiakas voi lähettää tai vastaanottaa tietoja palvelimelta, mikä tehdään käyttämällä send()- ja recive()-funktioita samalla tavalla kuin palvelin lähettää/vastaanottaa dataa asiakkaalta.

4. Sulje

Kun tiedonvaihto on valmis, asiakkaan on myös suljettava luotu socket ja vapautettava järjestelmäresurssit close()-funktiolla samalla tavalla kuin palvelin.

Socket-ohjelmoinnin yleiset ongelmat ja niiden korjaukset

  • Yhteyshäiriöt: Yhteyshäiriöiden välttämiseksi meidän tulee varmistaa, että asiakas yrittää muodostaa yhteyden oikeaan verkkoon IP-osoite ja portti .
  • Portin sidontavirheet: Nämä virheet tapahtuvat, kun portti on jo toisen sovelluksen käytössä tässä skenaariossa portin sidonta epäonnistuu. Yritä käyttää toista porttia tai sulje edellinen sovellus portin avulla.
  • Estoliitännät: Oletusarvoisesti pistokkeet estävät. Tämä tarkoittaa, että kutsut, kuten accept() tai recv(), odottavat toistaiseksi, jos asiakasyhteyttä tai dataa ei ole. Voit tarvittaessa asettaa pistorasian estotilaan.
Luo tietokilpailu