Socket Unix - Funciones principales

Este capítulo describe las funciones básicas del socket necesarias para escribir un cliente y un servidor TCP completos.

El siguiente diagrama muestra la interacción completa entre el cliente y el servidor:

La función del enchufe

Para realizar E / S de red, lo primero que debe hacer un proceso es llamar a la función socket, especificando el tipo de protocolo de comunicación deseado y familia de protocolos, etc.

#include <sys/types.h>
#include <sys/socket.h>

int socket (int family, int type, int protocol);

Esta llamada devuelve un descriptor de socket que puede usar en llamadas posteriores al sistema o -1 en caso de error.

Parámetros

family - Especifica la familia de protocolos y es una de las constantes que se muestran a continuación -

Familia Descripción
AF_INET Protocolos IPv4
AF_INET6 Protocolos IPv6
AF_LOCAL Protocolos de dominio Unix
AF_ROUTE Enrutamiento de enchufes
AF_KEY Toma de Ket

Este capítulo no cubre otros protocolos excepto IPv4.

type- Especifica el tipo de enchufe que desea. Puede tomar uno de los siguientes valores:

Tipo Descripción
SOCK_STREAM Toma de corriente
SOCK_DGRAM Toma de datagrama
SOCK_SEQPACKET Socket de paquete secuenciado
SOCK_RAW Toma sin procesar

protocol - El argumento debe establecerse en el tipo de protocolo específico que se indica a continuación, o 0 para seleccionar el valor predeterminado del sistema para la combinación dada de familia y tipo -

Protocolo Descripción
IPPROTO_TCP Protocolo de transporte TCP
IPPROTO_UDP Protocolo de transporte UDP
IPPROTO_SCTP Protocolo de transporte SCTP

La función de conexión

La función de conexión es utilizada por un cliente TCP para establecer una conexión con un servidor TCP.

#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

Esta llamada devuelve 0 si se conecta correctamente al servidor; de lo contrario, devuelve -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • serv_addr - Es un puntero a struct sockaddr que contiene la dirección IP y el puerto de destino.

  • addrlen - Configúrelo en sizeof (struct sockaddr).

La función de enlace

El bind función asigna una dirección de protocolo local a un socket. Con los protocolos de Internet, la dirección del protocolo es la combinación de una dirección IPv4 de 32 bits o una dirección IPv6 de 128 bits, junto con un número de puerto TCP o UDP de 16 bits. Esta función solo la llama el servidor TCP.

#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, struct sockaddr *my_addr,int addrlen);

Esta llamada devuelve 0 si se une con éxito a la dirección; de lo contrario, devuelve -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • my_addr - Es un puntero a struct sockaddr que contiene la dirección IP local y el puerto.

  • addrlen - Configúrelo en sizeof (struct sockaddr).

Puedes poner tu dirección IP y tu puerto automáticamente

Un valor 0 para el número de puerto significa que el sistema elegirá un puerto aleatorio, y el valor INADDR_ANY para la dirección IP significa que la dirección IP del servidor se asignará automáticamente.

server.sin_port = 0;  		     
server.sin_addr.s_addr = INADDR_ANY;

NOTE- Todos los puertos por debajo de 1024 están reservados. Puede configurar un puerto por encima de 1024 y por debajo de 65535 a menos que sean los que están utilizando otros programas.

La función de escuchar

La función de escucha es llamada solo por un servidor TCP y realiza dos acciones:

  • La función de escucha convierte un socket no conectado en un socket pasivo, lo que indica que el kernel debe aceptar solicitudes de conexión entrantes dirigidas a este socket.

  • El segundo argumento de esta función especifica el número máximo de conexiones que el núcleo debe poner en cola para este socket.

#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd,int backlog);

Esta llamada devuelve 0 en caso de éxito, de lo contrario, devuelve -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • backlog - Es el número de conexiones permitidas.

La función de aceptar

La función de aceptación es llamada por un servidor TCP para devolver la siguiente conexión completada desde el frente de la cola de conexiones completadas. La firma de la llamada es la siguiente:

#include <sys/types.h>
#include <sys/socket.h>

int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

Esta llamada devuelve un descriptor no negativo en caso de éxito; de lo contrario, devuelve -1 en caso de error. Se supone que el descriptor devuelto es un descriptor de socket de cliente y todas las operaciones de lectura y escritura se realizarán en este descriptor para comunicarse con el cliente.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • cliaddr - Es un puntero a struct sockaddr que contiene la dirección IP y el puerto del cliente.

  • addrlen - Configúrelo en sizeof (struct sockaddr).

La función de envío

La función de envío se utiliza para enviar datos a través de conectores de flujo o conectores de datagramas CONECTADOS. Si desea enviar datos a través de sockets de datagramas NO CONECTADOS, debe usar la función sendto ().

Puede usar la llamada al sistema write () para enviar datos. Su firma es la siguiente:

int send(int sockfd, const void *msg, int len, int flags);

Esta llamada devuelve el número de bytes enviados, de lo contrario, devolverá -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • msg - Es un puntero a los datos que desea enviar.

  • len - Es la longitud de los datos que desea enviar (en bytes).

  • flags - Está configurado en 0.

La función recv

La función recv se utiliza para recibir datos a través de sockets de flujo o sockets de datagramas CONECTADOS. Si desea recibir datos a través de sockets de datagramas NO CONECTADOS, debe usar recvfrom ().

Puede usar la llamada al sistema read () para leer los datos. Esta llamada se explica en el capítulo de funciones auxiliares.

int recv(int sockfd, void *buf, int len, unsigned int flags);

Esta llamada devuelve el número de bytes leídos en el búfer; de lo contrario, devolverá -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • buf - Es el búfer para leer la información.

  • len - Es la longitud máxima del búfer.

  • flags - Está configurado en 0.

La función sendto

La función sendto se utiliza para enviar datos a través de conectores de datagramas NO CONECTADOS. Su firma es la siguiente:

int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

Esta llamada devuelve el número de bytes enviados; de lo contrario, devuelve -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • msg - Es un puntero a los datos que desea enviar.

  • len - Es la longitud de los datos que desea enviar (en bytes).

  • flags - Está configurado en 0.

  • to - Es un puntero a struct sockaddr para el host al que se deben enviar los datos.

  • tolen - Se establece en sizeof (struct sockaddr).

La función recvfrom

La función recvfrom se utiliza para recibir datos de sockets de datagramas NO CONECTADOS.

int recvfrom(int sockfd, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen);

Esta llamada devuelve el número de bytes leídos en el búfer; de lo contrario, devuelve -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • buf - Es el búfer para leer la información.

  • len - Es la longitud máxima del búfer.

  • flags - Está configurado en 0.

  • from - Es un puntero a struct sockaddr para el host donde se deben leer los datos.

  • fromlen - Se establece en sizeof (struct sockaddr).

La función de cierre

La función de cierre se utiliza para cerrar la comunicación entre el cliente y el servidor. Su sintaxis es la siguiente:

int close( int sockfd );

Esta llamada devuelve 0 en caso de éxito, de lo contrario, devuelve -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

La función de apagado

La función de apagado se utiliza para cerrar correctamente la comunicación entre el cliente y el servidor. Esta función ofrece más control en comparación con la función de cierre . A continuación se muestra la sintaxis de apagado :

int shutdown(int sockfd, int how);

Esta llamada devuelve 0 en caso de éxito, de lo contrario, devuelve -1 en caso de error.

Parámetros

  • sockfd - Es un descriptor de socket devuelto por la función socket.

  • how - Pon uno de los números -

    • 0 - indica que la recepción no está permitida,

    • 1 - indica que el envío no está permitido y

    • 2- indica que no se permiten tanto el envío como la recepción. Cuando cómo se establece en 2, es lo mismo que close ().

La función de selección

La función de selección indica cuál de los descriptores de archivo especificados está listo para leer, para escribir o tiene una condición de error pendiente.

Cuando una aplicación llama a recv o recvfrom , se bloquea hasta que llegan datos para ese socket. Una aplicación podría estar realizando otro procesamiento útil mientras el flujo de datos entrante está vacío. Otra situación es cuando una aplicación recibe datos de varios sockets.

Llamar a recv o recvfrom en un socket que no tiene datos en su cola de entrada evita la recepción inmediata de datos de otros sockets. La llamada a la función select resuelve este problema al permitir que el programa sondee todos los identificadores de socket para ver si están disponibles para operaciones de lectura y escritura sin bloqueo.

A continuación se muestra la sintaxis de select -

int select(int  nfds, fd_set  *readfds, fd_set  *writefds, fd_set *errorfds, struct timeval *timeout);

Esta llamada devuelve 0 en caso de éxito, de lo contrario, devuelve -1 en caso de error.

Parámetros

  • nfds- Especifica el rango de descriptores de archivo que se probarán. La función select () prueba los descriptores de archivo en el rango de 0 a nfds-1

  • readfds- Apunta a un objeto de tipo fd_set que, en la entrada, especifica los descriptores de archivo que se verificarán si están listos para leer, y en la salida, indica qué descriptores de archivos están listos para leer. Puede ser NULL para indicar un conjunto vacío.

  • writefds- Apunta a un objeto de tipo fd_set que, en la entrada, especifica los descriptores de archivo que se verificarán para saber si están listos para escribir, y en la salida, indica qué descriptores de archivos están listos para escribir. Puede ser NULL para indicar un conjunto vacío.

  • exceptfds- Apunta a un objeto de tipo fd_set que, en la entrada, especifica los descriptores de archivo que se verificarán en busca de condiciones de error pendientes, y en la salida indica qué descriptores de archivo tienen condiciones de error pendientes. Puede ser NULL para indicar un conjunto vacío.

  • timeout- Apunta a una estructura timeval que especifica cuánto tiempo la llamada de selección debe sondear los descriptores para una operación de E / S disponible. Si el valor del tiempo de espera es 0, la selección volverá inmediatamente. Si el argumento de tiempo de espera es NULL, entonces select bloqueará hasta que al menos un identificador de archivo / socket esté listo para una operación de E / S disponible. De lo contrario, select regresará después de que haya transcurrido el tiempo de espera O cuando al menos un descriptor de archivo / conector esté listo para una operación de E / S.

El valor de retorno de select es el número de identificadores especificados en los conjuntos de descriptores de archivos que están listos para E / S. Si se alcanza el límite de tiempo especificado por el campo de tiempo de espera, seleccione return 0. Existen las siguientes macros para manipular un conjunto de descriptores de archivo:

  • FD_CLR(fd, &fdset)- Borra el bit del descriptor de archivo fd en el conjunto de descriptores de archivo fdset.

  • FD_ISSET(fd, &fdset)- Devuelve un valor distinto de cero si el bit para el descriptor de archivo fd está establecido en el conjunto de descriptores de archivo al que apunta fdset , y 0 en caso contrario.

  • FD_SET(fd, &fdset) - Establece el bit para el descriptor de archivo fd en el conjunto de descriptores de archivo fdset.

  • FD_ZERO(&fdset) - Inicializa el conjunto de descriptores de archivo fdset para que tenga cero bits para todos los descriptores de archivos.

El comportamiento de estas macros no está definido si el argumento fd es menor que 0 o mayor o igual que FD_SETSIZE.

Ejemplo

fd_set fds;

struct timeval tv;

/* do socket initialization etc.
tv.tv_sec = 1;
tv.tv_usec = 500000;

/* tv now represents 1.5 seconds */
FD_ZERO(&fds);

/* adds sock to the file descriptor set */
FD_SET(sock, &fds); 

/* wait 1.5 seconds for any data to be read from any single socket */
select(sock+1, &fds, NULL, NULL, &tv);

if (FD_ISSET(sock, &fds)) {
   recvfrom(s, buffer, buffer_len, 0, &sa, &sa_len);
   /* do something */
}
else {
   /* do something else */
}