Berkeley Sockets es una interfaz de programación de aplicaciones (API) para sockets de dominio de Internet y sockets de dominio Unix , utilizada para la comunicación entre procesos (IPC). Generalmente se implementa como una biblioteca de módulos enlazables. Su origen se remonta al sistema operativo Unix 4.2BSD , lanzado en 1983.
Un socket es una representación abstracta ( identificador ) del extremo local de una ruta de comunicación de red. La API de sockets de Berkeley lo representa como un descriptor de archivo, siguiendo la filosofía de Unix, que proporciona una interfaz común para la entrada y salida de flujos de datos.
Los sockets de Berkeley evolucionaron con pocas modificaciones, pasando de ser un estándar de facto a un componente de la especificación POSIX . El término sockets POSIX es esencialmente sinónimo de sockets de Berkeley , pero también se les conoce como sockets BSD , en referencia a su primera implementación en la distribución de software de Berkeley .
Historia e implementaciones
Los sockets de Berkeley se originaron con el sistema operativo Unix 4.2 BSD , lanzado en 1983, como interfaz de programación. Sin embargo, no fue hasta 1989 que la Universidad de California, Berkeley, pudo lanzar versiones del sistema operativo y la biblioteca de red libres de las restricciones de licencia del sistema Unix propietario de AT&T Corporation .
Todos los sistemas operativos modernos implementan una versión de la interfaz de sockets de Berkeley. Esta se convirtió en la interfaz estándar para las aplicaciones que se ejecutan en Internet . Incluso la implementación de Winsock para MS Windows, creada por desarrolladores independientes, sigue fielmente este estándar.
La API de sockets BSD está escrita en el lenguaje de programación C. La mayoría de los demás lenguajes de programación proporcionan interfaces similares, generalmente escritas como una biblioteca envolvente basada en la API de C. [ 1 ]
Sockets BSD y POSIX
A medida que la API de sockets de Berkeley evolucionó y finalmente dio lugar a la API de sockets POSIX, [ 2 ] ciertas funciones fueron descontinuadas o eliminadas y reemplazadas por otras. La API POSIX también está diseñada para ser reentrante y admite IPv6.
Alternatives
The STREAMS-based Transport Layer Interface (TLI) API offers an alternative to the socket API. Many systems that provide the TLI API also provide the Berkeley socket API.
Non-Unix systems often expose the Berkeley socket API with a translation layer to a native networking API. Plan 9[3] and Genode[4] use file-system APIs with control files rather than file-descriptors.
Header files
The Berkeley socket interface is defined in several header files. The names and content of these files differ slightly between implementations. In general, they include:
Socket API functions

The Berkeley socket API typically provides the following functions:
socket()creates a new socket of a certain type, identified by an integer number, and allocates system resources to it.bind()is typically used on the server side, and associates a socket with a socket address structure, i.e. a specified local IP address and a port number.listen()is used on the server side, and causes a bound TCP socket to enter listening state.connect()is used on the client side, and assigns a free local port number to a socket. In case of a TCP socket, it causes an attempt to establish a new TCP connection.accept()is used on the server side. It accepts a received incoming attempt to create a new TCP connection from the remote client, and creates a new socket associated with the socket address pair of this connection.send(),recv(),sendto(), andrecvfrom()are used for sending and receiving data. The standard functionswrite()andread()may also be used.close()causes the system to release resources allocated to a socket. In case of TCP, the connection is terminated.gethostbyname()andgethostbyaddr()are used to resolve host names and addresses. IPv4 only.getaddrinfo()andfreeaddrinfo()are used to resolve host names and addresses. IPv4, IPv6.select()is used to suspend, waiting for one or more of a provided list of sockets to be ready to read, ready to write, or that have errors.poll()Se utiliza para comprobar el estado de un socket en un conjunto de sockets. Se puede probar el conjunto para ver si se puede escribir o leer en algún socket, o si se ha producido algún error.getsockopt()Se utiliza para recuperar el valor actual de una opción de socket específica para el socket especificado.setsockopt()Se utiliza para establecer una opción de socket particular para el socket especificado.
enchufe
La función socket()crea un punto final para la comunicación y devuelve un descriptor de archivo para el socket. Utiliza tres argumentos:
domain, que especifica la familia de protocolos del socket creado. Por ejemplo:- PF_INET para el protocolo de red IPv4 (solo IPv4)
- PF_INET6 para IPv6 (y en algunos casos, compatible con versiones anteriores de IPv4)
- PF_UNIX para socket local (usando un nodo de sistema de archivos especial)
type, uno de:- SOCK_STREAM (servicio confiable orientado a flujos o sockets de flujo )
- SOCK_DGRAM (servicio de datagramas o sockets de datagramas )
- SOCK_SEQPACKET (servicio confiable de paquetes secuenciados)
- SOCK_RAW (protocolos sin procesar sobre la capa de red)
protocolEspecifica el protocolo de transporte que se utilizará. Los más comunes son IPPROTO_TCP , IPPROTO_SCTP , IPPROTO_UDP e IPPROTO_DCCP . Estos protocolos se especifican en el archivo . El valor 0 permite seleccionar un protocolo predeterminado del dominio y tipo seleccionados.<netinet/in.h>
La función devuelve -1 si se produjo un error. En caso contrario, devuelve un número entero que representa el descriptor recién asignado.
unir
bind()asocia un socket con una dirección. Cuando se crea un socket con socket(), solo se le asigna una familia de protocolo, pero no una dirección. Esta asociación debe realizarse antes de que el socket pueda aceptar conexiones de otros hosts. La función tiene tres argumentos:
sockfd, un descriptor que representa el socketmy_addr, un puntero a unasockaddrestructura que representa la dirección a la que enlazar.addrlen, un campo de tiposocklen_tque especifica el tamaño de lasockaddrestructura.
bind()Devuelve 0 si la operación se realiza correctamente y -1 si se produce un error.
escuchar
Después de que un socket se ha asociado con una dirección, listen()lo prepara para conexiones entrantes. Sin embargo, esto solo es necesario para los modos de datos orientados a flujo (orientados a conexión), es decir, para los tipos de socket ( SOCK_STREAM, SOCK_SEQPACKET). listen()requiere dos argumentos:
sockfd, un descriptor de socket válido.backlog, un número entero que representa la cantidad de conexiones pendientes que pueden estar en cola en un momento dado. El sistema operativo suele poner un límite a este valor.
Una vez aceptada la conexión, se extrae de la cola. Si la operación es exitosa, se devuelve 0. Si se produce un error, se devuelve -1.
aceptar
Cuando una aplicación está a la espera de conexiones orientadas a flujo desde otros hosts, se le notifica de dichos eventos (véase select()la función) y debe inicializar la conexión utilizando la función accept(). Esta crea un nuevo socket para cada conexión y elimina la conexión de la cola de escucha. La función tiene los siguientes argumentos:
sockfd, el descriptor del socket de escucha que tiene la conexión en cola.cliaddr, un puntero a una estructura sockaddr para recibir la información de la dirección del cliente.addrlen, un puntero a unasocklen_tubicación que especifica el tamaño de la estructura de dirección del cliente pasada aaccept(). Cuandoaccept()regresa, esta ubicación contiene el tamaño (en bytes) de la estructura.
accept()Devuelve el nuevo descriptor de socket para la conexión aceptada, o el valor -1 si se produce un error. Toda la comunicación posterior con el host remoto se realizará a través de este nuevo socket.
Los sockets de datagramas no requieren procesamiento, accept()ya que el receptor puede responder inmediatamente a la solicitud utilizando el socket de escucha.
conectar
connect()Establece un enlace de comunicación directo con un host remoto específico, identificado por su dirección, a través de un socket, identificado por su descriptor de archivo.
Al utilizar un protocolo orientado a la conexión , se establece una conexión. Algunos tipos de protocolos no requieren conexión, especialmente el Protocolo de Datagramas de Usuario (UDP ). Al utilizarse con protocolos sin conexión, connectse define la dirección remota para enviar y recibir datos, lo que permite el uso de funciones como sendy recv. En estos casos, la función connect impide la recepción de datagramas de otras fuentes.
connect()Devuelve un entero que representa el código de error: 0 representa éxito, mientras que –1 representa un error. Históricamente, en los sistemas derivados de BSD, el estado de un descriptor de socket es indefinido si la llamada a falla (como se especifica en la Especificación Única de Unix ), por lo tanto, las aplicaciones portátiles deben cerrar el descriptor de socket inmediatamente y obtener un nuevo descriptor con , en caso de que la llamada a falle. [ 5 ]connectsocket()connect()
obtenerhostpornombre y obtenerhostpordirección
Las funciones gethostbyname()y gethostbyaddr()se utilizan para resolver nombres de host y direcciones en el sistema de nombres de dominio u otros mecanismos de resolución del host local (por ejemplo, /etc/hostsbúsqueda). Devuelven un puntero a un objeto de tipo struct hostent, que describe un host de protocolo de Internet . Las funciones utilizan los siguientes argumentos:
nameespecifica el nombre del host.addrespecifica un puntero questruct in_addrcontiene la dirección del host.lenespecifica la longitud, en bytes, deaddr.typeespecifica el tipo de familia de direcciones (por ejemplo,AF_INET) de la dirección del host.
Las funciones devuelven un valor en caso de error, en cuyo caso se puede comprobar NULLel entero externo para determinar si se trata de un fallo temporal o de un host no válido o desconocido. De lo contrario, se devuelve un valor válido.h_errnostruct hostent*
Estas funciones no son estrictamente un componente de la API de sockets BSD, pero a menudo se utilizan junto con las funciones de la API para buscar un host. Estas funciones ahora se consideran interfaces heredadas para consultar el sistema de nombres de dominio. Se han definido nuevas funciones que son completamente independientes del protocolo (compatibles con IPv6). Estas nuevas funciones son getaddrinfo() y getnameinfo() , y se basan en una nueva estructura de datos . [ 6 ][[addrinfo]]
Este par de funciones apareció al mismo tiempo que la API de sockets BSD propiamente dicha en 4.2BSD (1983), [ 7 ] el mismo año en que se creó DNS por primera vez. Las primeras versiones no consultaban DNS y solo realizaban búsquedas en /etc/hosts. La versión 4.3BSD (1984) añadió DNS de forma rudimentaria. La implementación actual que utiliza Name Service Switch deriva de Solaris y posteriormente de NetBSD 1.4 (1999). [ 8 ] Inicialmente definido para NIS+ , NSS hace que DNS sea solo una de las muchas opciones de búsqueda para estas funciones y su uso puede deshabilitarse incluso hoy en día. [ 9 ]
Protocolo y atención a las familias
La API de sockets de Berkeley es una interfaz general para redes y comunicación entre procesos, y admite el uso de varios protocolos de red y arquitecturas de direcciones.
A continuación se muestra una selección de familias de protocolos (precedidas por el identificador simbólico estándar) definidas en una implementación moderna de Linux o BSD :
Se crea un socket para comunicaciones con la socket()función, especificando la familia de protocolos deseada ( PF_ -identificador) como argumento.
El concepto de diseño original de la interfaz de socket distinguía entre tipos de protocolo (familias) y los tipos de dirección específicos que cada uno podía usar. Se preveía que una familia de protocolos pudiera tener varios tipos de dirección. Los tipos de dirección se definían mediante constantes simbólicas adicionales, utilizando el prefijo AF en lugar de PF . Los identificadores AF están destinados a todas las estructuras de datos que tratan específicamente con el tipo de dirección y no con la familia de protocolos. Sin embargo, este concepto de separación entre protocolo y tipo de dirección no ha encontrado apoyo en la implementación, y las constantes AF se definieron mediante el identificador de protocolo correspondiente, dejando la distinción entre constantes AF y PF como un argumento técnico sin consecuencias prácticas. De hecho, existe mucha confusión en el uso correcto de ambas formas. [ 11 ]
La especificación POSIX.1—2008 no especifica ninguna constante PF , sino solo constantes AF [ 12 ].
Zócalos sin procesar
Los sockets sin procesar proporcionan una interfaz sencilla que evita el procesamiento por parte de la pila TCP/IP del host. Permiten la implementación de protocolos de red en el espacio de usuario y facilitan la depuración de la pila de protocolos. [ 13 ] Algunos servicios, como ICMP , que operan en la capa de Internet del modelo TCP/IP, utilizan sockets sin procesar .
Modo de bloqueo y modo sin bloqueo
Los sockets de Berkeley pueden funcionar en uno de dos modos: bloqueante o no bloqueante.
Un socket bloqueante no devuelve el control hasta que haya enviado (o recibido) parte o la totalidad de los datos especificados para la operación. Es normal que un socket bloqueante no envíe todos los datos. La aplicación debe comprobar el valor de retorno para determinar cuántos bytes se han enviado o recibido y debe reenviar cualquier dato que aún no se haya procesado. [ 14 ] Al usar sockets bloqueantes, se debe prestar especial atención a accept(), ya que puede seguir bloqueándose después de indicar que está disponible si un cliente se desconecta durante la fase de conexión.
Un socket no bloqueante devuelve el contenido del búfer de recepción y continúa inmediatamente. Si no se implementan correctamente, los programas que utilizan sockets no bloqueantes son particularmente susceptibles a condiciones de carrera debido a variaciones en la velocidad del enlace de red.
Normalmente, un socket se configura en modo bloqueante o no bloqueante mediante las funciones fcntl e ioctl .
Tomas de terminación
El sistema operativo no libera los recursos asignados a un socket hasta que este se cierra. Esto es especialmente importante si la llamada de conexión falla y se reintenta.
Cuando una aplicación cierra un socket, solo se destruye la interfaz del socket. Es responsabilidad del kernel destruir el socket internamente. En ocasiones, un socket puede entrar en un estado TIME_WAIT , en el lado del servidor, durante un máximo de 4 minutos. [ 15 ]
En los sistemas SVR4 , el uso de close()puede descartar datos. El uso de shutdown()o SO_LINGER puede ser necesario en estos sistemas para garantizar la entrega de todos los datos. [ 16 ]
Ejemplo cliente-servidor usando TCP
El Protocolo de Control de Transmisión (TCP) es un protocolo orientado a la conexión que proporciona diversas características de corrección de errores y rendimiento para la transmisión de flujos de bytes. Un proceso crea un socket TCP llamando a la socket()función con los parámetros para la familia de protocolos ( PF INET , PF_INET6 ), el modo de socket para sockets de flujo ( SOCK_STREAM ) y el identificador de protocolo IP para TCP ( IPPROTO_TCP ).
Servidor
Para establecer un servidor TCP se siguen los siguientes pasos básicos:
- Creación de un socket TCP con una llamada a
socket(). - Vinculación del socket al puerto de escucha
bind()después de configurar el número de puerto. - Preparando el socket para escuchar conexiones (convirtiéndolo en un socket de escucha), con una llamada a
listen(). - Aceptando conexiones entrantes (
accept()). Esto bloquea el proceso hasta que se recibe una conexión entrante y devuelve un descriptor de socket para la conexión aceptada. El descriptor inicial permanece como un descriptor de escucha yaccept()puede volver a llamarse en cualquier momento con este socket, hasta que se cierre. - Comunicación con el host remoto mediante las funciones API
send()yrecv(), así como mediante las funciones de propósito generalwrite()yread(). - Cerrando cada toma que se abrió después de su uso con la función
close()
El siguiente programa crea un servidor TCP que escucha en el puerto número 1100:
#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h>#include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> int main ( void ) { int sockfd = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ); if ( sockfd == -1 ) { fprintf ( stderr , "¡Error al crear el socket! \n " ); return EXIT_FAILURE ; } struct sockaddr_in sa = { . sin_family = AF_INET , . sin_port = htons ( 1100 ), . sin_addr . s_addr = htonl ( INADDR_ANY ) }; if ( bind ( sockfd , ( struct sockaddr * ) & sa , sizeof ( sa )) == -1 ) { fprintf ( stderr , "¡Error al enlazar el socket! \n " ); close ( sockfd ); return EXIT_FAILURE ; } if ( listen ( sockfd , 10 ) == -1 ) { fprintf ( stderr , "¡Error al escuchar en el socket! \n " ); close ( sockfd ); return EXIT_FAILURE ; } while ( true ) { int connfd = accept ( sockfd , NULL , NULL ); if ( connfd == -1 ) { fprintf ( stderr , "¡Error al aceptar la conexión! \n " ); close ( sockfd ); returnEXIT_FAILURE ; } // realizar operaciones de lectura y escritura... // read(connfd, buff, size) if ( shutdown ( connfd , SHUT_RDWR ) == -1 ) { fprintf ( stderr , "¡Error al cerrar la conexión! \n " ); close ( connfd ); close ( sockfd ); return EXIT_FAILURE ; } close ( connfd ); }cerrar ( sockfd ); devolver SALIDA_ÉXITA ; }Cliente
La programación de una aplicación cliente TCP implica los siguientes pasos:
- Creando un socket TCP.
- Conectarse al servidor (
connect()), pasando unasockaddr_inestructura con elsin_familyvalor establecido en AF_INET , establecido en el puerto en el que el punto final está escuchando (en orden de bytes de red) y establecido en la dirección IP del servidor que escucha (también en orden de bytes de red).sin_portsin_addr - Comunicación con el host remoto mediante las funciones API
send()yrecv(), así como mediante las funciones de propósito generalwrite()yread(). - Cerrando cada enchufe que se abrió después de su uso con la función
close().
#include <stdio.h> #include <stdlib.h> #include <string.h>#include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> int main ( void ) { int sockfd = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ); if ( sockfd == -1 ) { fprintf ( stderr , "¡Error al crear el socket! \n " ); return EXIT_FAILURE ; } struct sockaddr_in sa = { . sin_family = AF_INET , . sin_port = htons ( 1100 ), }; int res = inet_pton ( AF_INET , "192.168.1.3" , & sa . sin_addr );if ( connect ( sockfd , ( struct sockaddr * ) & sa , sizeof ( sa )) == -1 ) { fprintf ( stderr , "¡Error al establecer la conexión! \n " ); close ( sockfd ); return EXIT_FAILURE ; } // realizar operaciones de lectura y escritura... close ( sockfd ); return EXIT_SUCCESS ; }Ejemplo cliente-servidor usando UDP
El Protocolo de Datagramas de Usuario (UDP) es un protocolo sin conexión que no garantiza la entrega de los paquetes. Estos pueden llegar desordenados, varias veces o no llegar nunca. Gracias a este diseño minimalista, UDP tiene una sobrecarga considerablemente menor que TCP. Al ser sin conexión, no existe el concepto de flujo o conexión permanente entre dos hosts. Dichos datos se denominan datagramas ( sockets de datagramas ).
El espacio de direcciones UDP, el espacio de números de puerto UDP (en terminología ISO, los TSAP ), es completamente independiente del de los puertos TCP.
Servidor
Una aplicación puede configurar un servidor UDP en el número de puerto 7654de la siguiente manera. El programa contiene un bucle infinito que recibe datagramas UDP con la función recvfrom().
#include <stdbool.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h>#include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h>int main ( void ) { struct sockaddr_in sa = { . sin_family = AF_INET , . sin_addr . s_addr = htonl ( INADDR_ANY ), . sin_port = htons ( 7654 ) }; char buffer [ 1024 ]; ssize_t recsize ; socklen_t fromlen = sizeof ( sa );int sock = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ); if ( bind ( sock , ( struct sockaddr * ) & sa , sizeof ( sa )) == -1 ) { fprintf ( stderr , "¡Error al enlazar el socket! \n " ); close ( sock ); return EXIT_FAILURE ; }while ( true ) { recsize = recvfrom ( sock , ( void * ) buffer , sizeof buffer , 0 , ( struct sockaddr * ) & sa , & fromlen ); if ( recsize < 0 ) { fprintf ( stderr , "%s \n " , strerror ( errno )); return EXIT_FAILURE ; } printf ( "recsize: %d \n " , ( int ) recsize ); sleep ( 1 ); printf ( "datagrama: %.*s \n " , ( int ) recsize , buffer ); } }Cliente
El siguiente es un programa cliente para enviar un paquete UDP que contiene la cadena "Hello, world!" a la dirección 127.0.0.1en el puerto número 7654.
#include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h>#include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h>int main ( void ) { struct sockaddr_in sa = { // La dirección es IPv4 . sin_family = AF_INET , // Las direcciones IPv4 son un uint32_t, convierte una representación de cadena de los octetos al valor apropiado . sin_addr . s_addr = inet_addr ( "127.0.0.1" ), // Los sockets son shorts sin signo, htons(x) asegura que x esté en orden de bytes de red, establece el puerto en 7654 . sin_port = htons ( 7654 ) }; char buffer [ 200 ]; strcpy ( buffer , "¡Hola, mundo!" );// Crea un socket de datagramas de Internet usando UDP int sock = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ); if ( sock == -1 ) { // Si el socket no se pudo inicializar, salir fprintf ( stderr , "¡Error al crear el socket! \n " ); return EXIT_FAILURE ; }// Enviar mensaje usando sendto() int bytes_sent = sendto ( sock , buffer , strlen ( buffer ), 0 , ( struct sockaddr * ) & sa , sizeof ( sa ));if ( bytes_sent < 0 ) { fprintf ( stderr , "Error al enviar el paquete: %s \n " , strerror ( errno )); return EXIT_FAILURE ; } close ( sock ); // cerrar el socket return 0 ; }En este código, bufferes un puntero a los datos que se van a enviar y buffer_lengthespecifica el tamaño de los datos.
Referencias
- ↑ Por ejemplo, en la clase Socket del lenguaje de programación Ruby
- ↑ "— Especificación POSIX.1-2008" . Opengroup.org . Consultado el 26 de julio de 2012 .
- ↑ "La organización de redes en el Plan 9" .
- ↑ "Pila TCP/IP de Linux como complemento VFS" .
- ↑ Stevens y Rago 2013 , pág. 607.
- ↑ POSIX.1-2004
- ↑ – Manual de funciones de la biblioteca de FreeBSD
- ↑ Conill, Ariadne (27 de marzo de 2022). "La tragedia de gethostbyname" . ariadne.space .
- ↑ – Manual de formatos de archivo de FreeBSD
- ↑ "netrom(4) — ax25-tools — Debian experimental — Debian Manpages" .
- ↑ Programación de redes UNIX Volumen 1, Tercera edición: La API de redes Sockets, W. Richard Stevens, Bill Fenner, Andrew M. Rudoff, Addison Wesley, 2003.
- ↑ "Especificaciones básicas de The Open Group, número 7" . Pubs.opengroup.org . Consultado el 26 de julio de 2012 .
- ↑ "Sockets TCP/IP sin procesar - Aplicaciones Win32" . 19 de enero de 2022.
- ↑ "Guía de Beej para la programación de redes" . Beej.us. 5 de mayo de 2007. Consultado el 26 de julio de 2012 .
- ↑ "terminating sockets" . Softlab.ntua.gr . Consultado el 26 de julio de 2012 .
- ↑ "ntua.gr - Programación de sockets UNIX en C - Preguntas frecuentes: Preguntas sobre clientes y servidores (TCP/SOCK_STREAM)" . Softlab.ntua.gr . Consultado el 26 de julio de 2012 .
La definición estándar de jure de la interfaz Sockets está contenida en el estándar POSIX, conocido como:
- Norma IEEE Std. 1003.1-2001 para tecnología de la información: interfaz de sistema operativo portátil (POSIX).
- Norma técnica de Open Group: Especificaciones básicas, edición 6, diciembre de 2001.
- ISO/IEC 9945:2002
La información sobre esta norma y el trabajo que se está realizando al respecto está disponible en el sitio web de Austin .
Las extensiones IPv6 a la API de sockets base están documentadas en los RFC 3493 y RFC 3542.
- Stevens, W. Richard; Rago, Stephen A. (24 de mayo de 2013). Programación avanzada en el entorno UNIX (Tercera ed.). Addison-Wesley Professional . ISBN 978-0321637734Consultado el 27 de febrero de 2015 .
Enlaces externos
- Documentos complementarios para programadores de UNIX (PSD: 20-1)
- Guía de Beej para la programación de redes - 2007
- Adaptación de programas Berkeley Socket a Winsock : documentación de Microsoft.
- Programación de sockets UNIX en C - Preguntas frecuentes - 1996
- Programación de redes Linux - Revista Linux , 1998
- socket de red
- Interfaces de programación de aplicaciones
- Distribución de software de Berkeley