stringtranslate.com

Socket de dominio Unix

En la informática cliente-servidor , un socket de dominio Unix es un socket Berkeley que permite intercambiar datos entre dos procesos que se ejecutan en el mismo ordenador host Unix o similar a Unix . [1] Esto es similar a un socket de dominio de Internet que permite intercambiar datos entre dos procesos que se ejecutan en diferentes ordenadores host.

Independientemente del rango de comunicación (mismo host o host diferente), [2] los programas informáticos Unix que realizan la comunicación por socket son similares. La única diferencia en el rango de comunicación es el método para convertir un nombre en el parámetro de dirección necesario para vincular la conexión del socket. Para un socket de dominio Unix , el nombre es un . Para un socket de dominio de Internet , el nombre es un . En cualquier caso, el nombre se denomina dirección . [3]/path/filenameIP address:Port number

Dos procesos pueden comunicarse entre sí si cada uno obtiene un socket. El proceso del servidor vincula su socket a una dirección , abre un canal de escucha y luego realiza un bucle continuo . Dentro del bucle, el proceso del servidor se pone en reposo mientras espera para aceptar una conexión de cliente. [4] Al aceptar una conexión de cliente, el servidor ejecuta una llamada al sistema de lectura que bloqueará wait . El cliente se conecta al socket del servidor a través de la dirección del servidor . Luego, el proceso del cliente escribe un mensaje para que el proceso del servidor lo lea. El algoritmo de la aplicación puede implicar múltiples interacciones de lectura/escritura. Al completarse el algoritmo, el cliente ejecuta [5] y el servidor ejecuta . [6]exit()close()

En el caso de un socket de dominio Unix , la dirección del socket es un /path/filenameidentificador. El servidor creará un semáforo/path/filename en el sistema de archivos para que actúe como un archivo de bloqueo . No se produce ninguna operación de E/S en este archivo cuando el cliente y el servidor se envían mensajes entre sí. [7]

Historia

Los sockets aparecieron por primera vez en Berkeley Software Distribution 4.2 (1983). [8] Se convirtieron en un estándar POSIX en 2000. [8] La interfaz de programación de aplicaciones se ha adaptado a prácticamente todas las implementaciones de Unix y a la mayoría de los demás sistemas operativos. [8]

Instanciación de socket

Tanto el servidor como el cliente deben crear una instancia de un objeto socket ejecutando la socket() llamada al sistema . Su uso es: [9]

int socket ( int dominio , int tipo , int protocolo );        

El domainparámetro debe ser uno de los siguientes rangos comunes de comunicación : [10]

  1. Dentro del mismo host utilizando la constante AF_UNIX[a]
  2. Entre dos hosts a través del protocolo IPv4 utilizando la constanteAF_INET
  3. Entre dos hosts a través del protocolo IPv6 utilizando la constanteAF_INET6
  4. Dentro del mismo host o entre dos hosts a través del Protocolo de Transmisión de Control de Flujo utilizando la constante SOCK_SEQPACKET[11]

La etiqueta de socket de dominio Unix se utiliza cuando el domainvalor del parámetro es AF_UNIX. La etiqueta de socket de dominio de Internet se utiliza cuando el domainvalor del parámetro es AF_INETo AF_INET6. [12]

El typeparámetro debe ser uno de los dos tipos de sockets más comunes: flujo o datagrama. [10] Hay un tercer tipo de socket disponible para el diseño experimental: sin procesar.

  1. SOCK_STREAMcreará un socket de flujo. Un socket de flujo proporciona un canal de comunicación confiable, bidireccional y orientado a la conexión entre dos procesos. Los datos se transmiten utilizando el Protocolo de control de transmisión (TCP). [10]
  2. SOCK_DGRAMcreará un socket de datagrama. [b] Un socket de datagrama no garantiza la confiabilidad y no tiene conexión . Como resultado, la transmisión es más rápida. Los datos se transportan utilizando el Protocolo de datagramas de usuario (UDP). [14]
  3. SOCK_RAWcreará un socket de datagrama de protocolo de Internet (IP) . Un socket sin formato omite la capa de transporte TCP/UDP y envía los paquetes directamente a la capa de red . [15]

En un socket de dominio Unix , los datos ( paquetes de red ) pasan entre dos procesos conectados a través de la capa de transporte , ya sea TCP o UDP. [16] En un socket de dominio de Internet , los datos pasan entre dos procesos conectados a través de la capa de transporte y el Protocolo de Internet (IP) de la capa de red , ya sea TCP/IP o UDP/IP. [16]

El protocolparámetro debe establecerse en cero para los sockets de flujo y datagrama. [2] Para los sockets sin procesar, el protocolparámetro debe establecerse en IPPROTO_RAW. [9]

Valor de retorno de socket()

socket_fd = socket ( int dominio , int tipo , int protocolo );         

Al igual que la llamada al sistema de archivos normal open(), la socket()llamada al sistema devuelve un descriptor de archivo . [2] [c] El sufijo del valor de retorno _fdrepresenta el descriptor de archivo .

Enlace del servidor a /ruta/nombre de archivo

Después de crear una instancia de un nuevo socket, el servidor vincula el socket a una dirección. En el caso de un socket de dominio Unix , la dirección es un /path/filename.

Dado que la dirección del socket puede ser un /path/filenameo un IP_address:Port_number, la interfaz de programación de aplicaciones de socket requiere que la dirección se configure primero en una estructura. Para un socket de dominio Unix , la estructura es: [17]

struct sockaddr_un { familia_sa_t familia_sol ; /* AF_UNIX */ char ruta_sol [ 92 ]; }         

El _unsufijo significa unix . Para un socket de dominio de Internet , el sufijo será o _inbien _in6. El sun_prefijo significa socket unix . [17]

Programa informático para crear y vincular un socket de dominio Unix de flujo : [7]

#include <stdlib.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <assert.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h>        /* Debe tener 91 caracteres o menos. Algunos similares a Unix tienen un poco más. */ /* Use el directorio /tmp solo para demostración. */ char * socket_address = "/tmp/mysocket.sock" ;    void main ( void ) { int server_socket_fd ; struct sockaddr_un sockaddr_un = { 0 }; int valor_de_retorno ;             servidor_socket_fd = socket ( AF_UNIX , SOCK_STREAM , 0 ); si ( servidor_socket_fd == -1 ) afirmar ( 0 );                /* Eliminar (tal vez) una ejecución anterior. */ remove ( socket_address );    /* Construye la estructura de la dirección de enlace. */ sockaddr_un . sun_family = AF_UNIX ; strcpy ( sockaddr_un . sun_path , socket_address );        valor_de_retorno = bind ( servidor_socket_fd , ( estructura sockaddr * ) y sockaddr_un , tamaño_de ( estructura sockaddr_un ) );             /* Si socket_address existe en el sistema de archivos, entonces el enlace fallará. */ if ( return_value == -1 ) assert ( 0 );          /* Se omitió el código de escucha y aceptación. */ }

El segundo parámetro de bind()es un puntero a struct sockaddr. Sin embargo, el parámetro que se pasa a la función es la dirección de un struct sockaddr_un. struct sockaddres una estructura genérica que no se utiliza. Se define en la declaración formal de parámetros de . Debido a que cada rango de comunicación tiene su propio parámetro real , esta estructura genérica se creó como un marcador de posición de conversión . [18]bind()

El servidor escucha una conexión

Después de vincularse a una dirección, el servidor abre un canal de escucha a un puerto ejecutando listen(). Su uso es: [19]

int escuchar ( int server_socket_fd , int backlog );      

Fragmento para escuchar:

si ( escuchar ( server_socket_fd , 4096 ) == -1 ) afirmar ( 0 );           

En el caso de un socket de dominio Unix , listen()lo más probable es que tenga éxito y devuelva 0. En el caso de un socket de dominio de Internet , si el puerto está en uso, listen()devuelve -1. [19]

El backlogparámetro establece el tamaño de la cola para las conexiones pendientes. [20] El servidor puede estar ocupado cuando un cliente ejecuta una connect()solicitud. Las solicitudes de conexión hasta este límite tendrán éxito. Si el valor de la cola de espera que se pasa supera el máximo predeterminado, se utiliza el valor máximo. [19]

El servidor acepta una conexión

Después de abrir un canal de escucha , el servidor entra en un bucle infinito . Dentro del bucle hay una llamada del sistema a accept(), que se pone a dormir. [4] La accept()llamada del sistema devolverá un descriptor de archivo cuando un proceso cliente ejecute connect(). [21]

Fragmento para aceptar una conexión:

int aceptar_socket_fd ; mientras ( 1 ) { aceptar_socket_fd = aceptar ( servidor_socket_fd , NULL , NULL ); si ( aceptar_socket_fd == -1 ) afirmar ( 0 );                    si ( accept_socket_fd ) > 0 ) /* el cliente está conectado */ }       

E/S de servidor en un socket

Cuando accept()devuelve un entero positivo, el servidor inicia un diálogo algorítmico con el cliente.

La entrada/salida del socket de flujo puede ejecutar las llamadas del sistema de archivos regulares de read()y write(). [6] Sin embargo, hay más control disponible si un socket de flujo ejecuta las llamadas del sistema específicas del socket de send()y recv(). Alternativamente, la entrada/salida del socket de datagrama debe ejecutar las llamadas del sistema específicas del socket de sendto()y recvfrom(). [22]

Para un socket de flujo básico, el servidor recibe datos con read( accept_socket_fd )y envía datos con write( accept_socket_fd ).

Fragmento para ilustrar la E/S en un socket de flujo básico:

int aceptar_socket_fd ; mientras ( 1 ) { aceptar_socket_fd = aceptar ( servidor_socket_fd , NULL , NULL ); si ( aceptar_socket_fd == -1 ) afirmar ( 0 );                    si ( accept_socket_fd > 0 ) { diálogo_algorítmico_del_servidor ( accept_socket_fd ); } }          #define TAMAÑO DE BÚFER 1024void diálogo_algorítmico_del_servidor ( int aceptar_socket_fd ) { char búfer_de_entrada [ TAMAÑO_DE_BÚFER ]; char búfer_de_salida [ TAMAÑO_DE_BÚFER ];             leer ( accept_socket_fd , input_buffer , BUFFER_SIZE );     si ( strcasecmp ( input_buffer , "hola" ) == 0 ) strcpy ( output_buffer , "Hola Mundo" ); de lo contrario si ( strcasecmp ( input_buffer , "ciao" ) == 0 ) strcpy ( output_buffer , "Ciao Mondo" ); de lo contrario strcpy ( output_buffer , "Hola Mundo" );                                escribir ( accept_socket_fd , buffer_de_salida , strlen ( buffer_de_salida ) + 1 ); }        

El servidor cierra una conexión

El diálogo algorítmico finaliza cuando el algoritmo concluye o read( accept_socket_fd )retorna < 1. [6] Para cerrar la conexión, ejecute la close()llamada del sistema: [6]

Fragmento para cerrar una conexión:

int aceptar_socket_fd ; mientras ( 1 ) { aceptar_socket_fd = aceptar ( servidor_socket_fd , NULL , NULL ); si ( aceptar_socket_fd == -1 ) afirmar ( 0 );                    si ( aceptar_socket_fd > 0 ) { diálogo_algorítmico_del_servidor ( aceptar_socket_fd ); cerrar ( aceptar_socket_fd ); } }             

Fragmento para ilustrar el final de un diálogo:

#define TAMAÑO DE BÚFER 1024void servidor_diálogo_algoritmo ( int aceptar_socket_fd ) { char buffer [ TAMAÑO_DE_BÚFER ]; int recuento_de_lecturas ;           /* Omitir diálogo algorítmico */ recuento_de_lecturas = leer ( aceptar_socket_fd , buffer , TAMAÑO_DE_BUFER ); si ( recuento_de_lecturas < 1 ) devolver ;              /* Omitir diálogo algorítmico */ }

El cliente crea una instancia y se conecta a /path/filename

Programa de computadora para que el cliente cree una instancia y conecte un socket: [5]

#include <stdlib.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <assert.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h>        /* Debe coincidir con la dirección de socket del servidor. */ char * socket_address = "/tmp/mysocket.sock" ;   void main ( void ) { int client_socket_fd ; struct sockaddr_un sockaddr_un = { 0 }; int valor_de_retorno ;             cliente_socket_fd = socket ( AF_UNIX , SOCK_STREAM , 0 ); si ( cliente_socket_fd == -1 ) afirmar ( 0 );                /* Construye la estructura de la dirección del cliente. */ sockaddr_un . sun_family = AF_UNIX ; strcpy ( sockaddr_un . sun_path , socket_address );        valor_de_retorno = conectar ( cliente_socket_fd , ( struct sockaddr * ) & sockaddr_un , tamaño_de ( struct sockaddr_un ) );             /* Si socket_address no existe en el sistema de archivos, */ /* o si la cola de solicitudes de conexión del servidor está llena, */ /* entonces connect() fallará. */ if ( return_value == -1 ) assert ( 0 );            /* cerrar( client_socket_fd ); <-- opcional */ salir ( SALIR_EXITO ); }  

E/S de cliente en un socket

Si connect()devuelve cero, el cliente puede iniciar un diálogo algorítmico con el servidor. El cliente puede enviar datos de transmisión a través de write( client_socket_fd )y puede recibir datos de transmisión a través de read( client_socket_fd ).

Fragmento para ilustrar la E/S del cliente en un socket de transmisión:

{ /* Omitir código de construcción */ return_value = connect ( client_socket_fd , ( struct sockaddr * ) & sockaddr_un , sizeof ( struct sockaddr_un ) );               si ( valor_de_retorno == -1 ) afirmar ( 0 );         si ( valor_de_retorno == 0 ) { diálogo_algorítmico_del_cliente ( fd_socket_del_cliente ); }           /* cerrar( client_socket_fd ); <-- opcional */ /* Cuando el proceso del cliente termina, */ /* si el servidor intenta read(), */ /* entonces read_count será 0 o -1. */ /* Este es un mensaje para que el servidor */ /* ejecute close(). */ exit ( EXIT_SUCCESS ); }       #define TAMAÑO DE BÚFER 1024void diálogo_algorítmico_del_cliente ( int cliente_socket_fd ) { char buffer [ TAMAÑO_DE_BÚFER ]; int recuento_de_lecturas ;           strcpy ( buffer , "hola" ); escribir ( client_socket_fd , buffer , strlen ( buffer ) + 1 ); recuento_de_lecturas = leer ( client_socket_fd , buffer , TAMAÑO_DE_BUFFER );                    si ( read_count > 0 ) pone ( buffer ); }        

Véase también

Referencias

  1. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1149. ISBN 978-1-59327-220-3Los sockets son un método de IPC que permite intercambiar datos entre aplicaciones, ya sea en el mismo host (computadora) o en diferentes hosts conectados por una red.
  2. ^ abc Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1150. ISBN 978-1-59327-220-3.
  3. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1150. ISBN 978-1-59327-220-3El servidor vincula su socket a una dirección conocida (nombre) para que los clientes puedan localizarlo .
  4. ^ ab Stevens, Richard W.; Fenner, Bill; Rudoff, Andrew M. (2004). Programación de redes Unix (3.ª ed.). Pearson Education. pág. 14. ISBN 81-297-0710-1Normalmente , el proceso del servidor se pone en reposo en la llamada a accept , esperando que llegue una conexión de cliente y sea aceptada.
  5. ^ ab Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1169. ISBN 978-1-59327-220-3.
  6. ^ abcd Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1159. ISBN 978-1-59327-220-3.
  7. ^ ab Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1166. ISBN 978-1-59327-220-3.
  8. ^ abc Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1149. ISBN 978-1-59327-220-3.
  9. ^ ab Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1153. ISBN 978-1-59327-220-3.
  10. ^ abc Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1151. ISBN 978-1-59327-220-3.
  11. ^ ab "Manual del programador de Linux (Unix - sockets para comunicación local entre procesos)". 30 de abril de 2018. Consultado el 22 de febrero de 2019 .
  12. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1197. ISBN 978-1-59327-220-3.
  13. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1183. ISBN 978-1-59327-220-3.
  14. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1152. ISBN 978-1-59327-220-3.
  15. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1184. ISBN 978-1-59327-220-3.
  16. ^ ab Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1181. ISBN 978-1-59327-220-3.
  17. ^ ab Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1165. ISBN 978-1-59327-220-3.
  18. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1154. ISBN 978-1-59327-220-3.
  19. ^ abc "Página del manual de Linux para listen()".
  20. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1157. ISBN 978-1-59327-220-3.
  21. ^ "Página del manual de Linux para accept()".
  22. ^ Kerrisk, Michael (2010). La interfaz de programación de Linux . No Starch Press. pág. 1160. ISBN 978-1-59327-220-3.

Notas

  1. ^ Alternativamente, se puede utilizar PF_UNIXo . [11] AF significa "Familia de direcciones" y PF significa "Familia de protocolos".AF_LOCAL
  2. ^ Un socket de datagrama no debe confundirse con un paquete de datagrama utilizado en la capa de red . [13]
  3. ^ En UNIX, todo es un archivo .