Programació de socket és una manera de connectar dos nodes en una xarxa per comunicar-se entre ells. Un sòcol (node) escolta en un port determinat a una IP mentre que l'altre sòcol s'acosta a l'altre per formar una connexió. El servidor forma el sòcol d'escolta mentre el client s'acosta al servidor.
La programació de socket s'utilitza àmpliament a les aplicacions de missatgeria instantània, en transmissió binària i en col·laboracions de documents, en plataformes de transmissió en línia, etc.
Exemple
En aquest programa C estem intercanviant un missatge de salutació entre servidor i client per demostrar el model client/servidor.
servidor.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; }
client.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; }
Compilant
gcc client.c -o clientgcc server.c -o server
Sortida
Client:Hello message sentHello from serverServer:Hello from clientHello message sentComponents de la programació de socket
1. Endolls
Endolls són un dels components bàsics utilitzats pel programa per accedir a la xarxa per comunicar-se amb altres processos/nodes a través de la xarxa. És simplement una combinació d'una adreça IP i un número de port que actua com a punt final per a la comunicació.
Exemple: 192.168.1.1:8080 on les dues parts separades pels dos punts representen el Adreça IP (192.168.1.1) i el número de port (8080).
Tipus de sòcols:
- Socket TCP (Socket de flux): Proporciona una comunicació fiable basada en connexió (p. ex. Protocol TCP ).
- Socket UDP (Socket de datagrama): Proporciona una comunicació sense connexió més ràpida però poc fiable (és a dir, Protocol UDP ).
2. Model client-servidor
El model client-servidor fa referència a l'arquitectura utilitzada en la programació de sockets on un client i un servidor interactuen entre ells per intercanviar informació o serveis. Aquesta arquitectura permet al client enviar sol·licituds de servei i al servidor processar i enviar resposta a aquestes peticions de servei.
Diagrama d'estats per al model de servidor i client
Diagrama d'estat per al model de servidor i client de SocketLa programació de socket en C és una manera potent de gestionar la comunicació de xarxa.
Creació d'un procés del costat del servidor
El servidor es crea seguint els passos següents:
transmissió de mitjans
1. Creació de sòcols
Aquest pas implica la creació del sòcol mitjançant la funció socket().
Paràmetres:
- sockfd: descriptor de socket un nombre enter (com un controlador de fitxer)
- domini: enter especifica el domini de comunicació. Utilitzem AF_LOCAL tal com es defineix a l'estàndard POSIX per a la comunicació entre processos del mateix host. Per a la comunicació entre processos en diferents hosts connectats per IPV4, utilitzem AF_INET i AF_I NET 6 per als processos connectats per IPV6.
- tipus: tipus de comunicació
SOCK_STREAM: TCP (orientat a connexió fiable)
SOCK_DGRAM: UDP (sense connexió no fiable) - protocol: Valor de protocol per a Protocol d'Internet (IP), que és 0. Aquest és el mateix número que apareix al camp de protocol a la capçalera IP d'un paquet. (man protocols per a més detalls)
sockfd = socket(domain type protocol)
2. Estableix l'opció de socket
Això ajuda a manipular les opcions per al sòcol a què fa referència el descriptor de fitxers sockfd. Això és completament opcional, però ajuda a reutilitzar l'adreça i el port. Evita errors com ara: adreça que ja està en ús.
Csetsockopt(sockfd level optname optval socklen_t optlen);
3. Lligar
Després de la creació del sòcol, la funció bind() lliga el sòcol a l'adreça i el número de port especificats a addr(estructura de dades personalitzada). En el codi d'exemple, enllacem el servidor al host local, per tant, utilitzem INADDR_ANY per especificar l'adreça IP.
C++bind(sockfd sockaddr *addr socklen_t addrlen);
Paràmetres:
- sockfd : descriptor de fitxer de socket creat mitjançant la funció socket().
- adr : punter a un struct sockaddr que conté l'adreça IP i el número de port per vincular el sòcol.
- adreça : longitud de l'estructura d'adr.
4. Escolta
En aquest pas, el servidor utilitza la funció listen() que posa el sòcol del servidor en un mode passiu on espera que el client s'acosti al servidor per establir una connexió. L'endarreriment defineix la longitud màxima a la qual pot créixer la cua de connexions pendents de sockfd. Si arriba una sol·licitud de connexió quan la cua està plena, el client pot rebre un error amb una indicació de ECONNREFUSED.
Clisten(sockfd backlog);
Paràmetres :
- sockfd : descriptor de fitxer de socket creat mitjançant la funció socket().
- endarreriment : número que representa la mida de la cua que conté les connexions pendents mentre el servidor està esperant per acceptar una connexió.
5. Acceptar
En aquest pas, el servidor extreu la primera sol·licitud de connexió de la cua de connexions pendents per a la presa d'escolta sockfd crea una nova presa connectada utilitzant el acceptar () funció i retorna un descriptor de fitxer nou que fa referència a aquest sòcol. En aquest punt s'estableix la connexió entre el client i el servidor i estan preparats per transferir dades.
Cnew_socket= accept(sockfd sockaddr *addr socklen_t *addrlen);
Paràmetres:
- sockfd : descriptor de fitxer de socket retornat per socket() i bind().
- adr : punter a un struct sockaddr que conté l'adreça IP i el número de port del client.
- adreça : punter a una variable que especifica la longitud de l'estructura d'adreces.
6. Enviar/Rebre
En aquest pas el servidor pot enviar o rebre dades del client.
Enviar(): per enviar dades al client
Csend(sockfd *buf len flags);
Paràmetres:
- sockfd : descriptor de fitxer de socket retornat per la funció socket().
- buf : punter a la memòria intermèdia que conté les dades a enviar.
- només : nombre de bytes de dades a enviar.
- banderes : nombre sencer que especifica diverses opcions de com s'envien les dades, normalment 0 s'utilitza per al comportament predeterminat.
Rebre(): per rebre les dades del client.
Crecv( sockfd *buf len flags);
Paràmetres:
- sockfd : descriptor de fitxer de socket retornat per la funció socket().
- buf : punter a la memòria intermèdia que conté les dades a emmagatzemar.
- només : nombre de bytes de dades a enviar.
- banderes : nombre sencer que especifica diverses opcions de com s'envien les dades, normalment 0 s'utilitza per al comportament predeterminat.
6. Tanca
Un cop finalitzat l'intercanvi d'informació, el servidor tanca el sòcol mitjançant la funció close() i allibera els recursos del sistema.
Cclose(fd);
Paràmetres:
- fd: descriptor de fitxer del socket.
Creació de processos del costat del client
Seguiu els passos següents per crear un procés del costat del client:
1. Connexió de presa
Aquest pas implica la creació del sòcol que es fa de la mateixa manera que la creació del sòcol del servidor
2. Connecta't
La crida al sistema connect() connecta el sòcol al qual fa referència el descriptor del fitxer sockfd amb l'adreça especificada per addr. L'adreça i el port del servidor s'especifiquen a addr.
C++connect(sockfd sockaddr *addr socklen_t addrlen);
Paràmetres
- sockfd : descriptor de fitxer de socket retornat per la funció socket().
- adr : punter a struct sockaddr que conté l'adreça IP i el número de port del servidor.
- adreça : mida de l'adr.
3. Enviar/Rebre
En aquest pas, el client pot enviar o rebre dades del servidor que es fa mitjançant les funcions send() i recieve() similars a com el servidor envia/reb dades del client.
4. Tanca
Un cop finalitzat l'intercanvi d'informació, el client també ha de tancar el sòcol creat i alliberar els recursos del sistema mitjançant la funció close() de la mateixa manera que ho fa el servidor.
Problemes comuns i les seves solucions a la programació de socket
- Errors de connexió: Per evitar errors de connexió, hem d'assegurar-nos que el client està intentant connectar-se al correcte Adreça IP i port .
- Errors d'enllaç de ports: Aquests errors es produeixen quan un port ja està en ús per una altra aplicació en aquest escenari, la vinculació a aquest port fallarà. Proveu d'utilitzar un port diferent o tanqueu l'aplicació anterior mitjançant el port.
- Sockets de bloqueig: Per defecte, els sòcols estan bloquejant. Això vol dir que les trucades com accept() o recv() esperaran indefinidament si no hi ha connexió o dades de client. Podeu configurar el sòcol en mode sense bloqueig si cal.