Programación de sockets en C/C++

¿Qué es la programación de sockets?
La programación de sockets es una forma de conectar dos Nodes en una red para comunicarse entre sí. Un socket (Node) escucha en un puerto particular en una IP, mientras que el otro socket se comunica con el otro para formar una conexión. El servidor forma el socket de escucha mientras el cliente se comunica con el servidor.

Diagrama de estado para el modelo de servidor y cliente

Diagrama de estado para el modelo de servidor y cliente de Socket

 

Etapas para servidor

1. Creación del zócalo:

int sockfd = socket(dominio, tipo, protocolo)

  • sockfd: descriptor de socket, un número entero (como un identificador de archivo)
  • dominio: entero, especifica el dominio de comunicación. Usamos AF_ LOCAL como se define en el estándar POSIX para la comunicación entre procesos en el mismo host. Para la comunicación entre procesos en diferentes hosts conectados por IPV4, usamos AF_INET y AF_I NET 6 para procesos conectados por IPV6.
  • tipo: tipo de comunicación
    SOCK_STREAM: TCP (confiable, orientado a la conexión)
    SOCK_DGRAM: UDP (no confiable, sin conexión)
  • protocolo: Valor de protocolo para el Protocolo de Internet (IP), que es 0. Este es el mismo número que aparece en el campo de protocolo en el encabezado IP de un paquete. (Protocolos de hombre para más detalles)

2. Setsockopt: Esto ayuda en la manipulación de opciones para el socket al que hace referencia el descriptor de archivo sockfd. Esto es completamente opcional, pero ayuda a reutilizar la dirección y el puerto. Previene errores como: “dirección ya en uso”.

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

3. Vincular:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Después de la creación del socket, la función de vinculación vincula el socket a la dirección y el número de puerto especificados en addr (estructura de datos personalizada). En el código de ejemplo, vinculamos el servidor al host local, por lo que usamos INADDR_ANY para especificar la dirección IP.

4. Escucha:

int listen(int sockfd, int backlog);

Pone el socket del servidor en modo pasivo, donde espera a que el cliente se acerque al servidor para establecer una conexión. El backlog define la longitud máxima a la que puede crecer la cola de conexiones pendientes para sockfd. Si llega una solicitud de conexión cuando la cola está llena, el cliente puede recibir un error con una indicación de ECONNREFUSED.

5. Aceptar:

int new_socket= accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Extrae la primera solicitud de conexión en la cola de conexiones pendientes para el socket de escucha, sockfd, crea un nuevo socket conectado y devuelve un nuevo descriptor de archivo que hace referencia a ese socket. En este punto, se establece la conexión entre el cliente y el servidor, y están listos para transferir datos.

Etapas para Cliente

  • Conexión de socket: exactamente igual que la creación del socket del servidor
  • Conectar: ​​la llamada al sistema connect() conecta el socket al que hace referencia el descriptor de archivo sockfd a la dirección especificada por addr. La dirección y el puerto del servidor se especifican en addr.

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

GeeksforGeeks-CPP-Foundation-Course

Implementación
Aquí estamos intercambiando un mensaje de saludo entre el servidor y el cliente para demostrar el modelo cliente/servidor.

  • Servidor.c

C

// Server side C/C++ program to demonstrate Socket
// programming
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
int main(int argc, char const* argv[])
{
    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int 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,
                  (socklen_t*)&addrlen))
        < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    valread = read(new_socket, buffer, 1024);
    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
    shutdown(server_fd, SHUT_RDWR);
    return 0;
}
  • cliente.c

C

// Client side C/C++ program to demonstrate Socket
// programming
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
  
int main(int argc, char const* argv[])
{
    int sock = 0, valread, client_fd;
    struct sockaddr_in serv_addr;
    char* hello = "Hello from client";
    char buffer[1024] = { 0 };
    if ((sock = 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 ((client_fd
         = connect(sock, (struct sockaddr*)&serv_addr,
                   sizeof(serv_addr)))
        < 0) {
        printf("\nConnection Failed \n");
        return -1;
    }
    send(sock, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    valread = read(sock, buffer, 1024);
    printf("%s\n", buffer);
  
    // closing the connected socket
    close(client_fd);
    return 0;
}

Compilando:

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

Producción:

Client:Hello message sent
Hello from server
Server:Hello from client
Hello message sent

Siguiente: Programación de sockets en C/C++: manejo de múltiples clientes en el servidor sin subprocesos múltiples
 

Este artículo es una contribución de Akshat Sinha . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *