Llamadas al sistema
getaddrinfo()
La funciΓ³n getaddrinfo
es una parte esencial del desarrollo de redes en C/C++. Permite a los programas resolver nombres de host y servicios, lo que significa que puede traducir un nombre de host (como www.ejemplo.com) a una direcciΓ³n IP y viceversa. Esto es especialmente ΓΊtil en situaciones en las que necesitas establecer una conexiΓ³n de red y necesitas saber la direcciΓ³n IP del host o el nombre del host a partir de una direcciΓ³n IP.
Aun asi, su uso es bastante simple. Ayuda a configurar las estructuras que necesitarΓ‘ mΓ‘s adelante.
Sintaxis
node
: El nombre del host o la direcciΓ³n IP que deseas resolver.service
: El nΓΊmero del puerto o el nombre del servicio al que deseas conectarte.hints
: Una estructuraaddrinfo
que proporciona pistas sobre el tipo de conexiΓ³n que estΓ‘s buscando.res
: Un puntero a un puntero de estructuraaddrinfo
que se llenarΓ‘ con los resultados.
La funciΓ³n devuelve 0 si tiene Γ©xito y un valor negativo si ocurre un error. El resultado de la funciΓ³n, es decir, la lista de estructuras addrinfo
, se almacena en el puntero doble res
. Es importante liberar esta memoria utilizando freeaddrinfo()
una vez que ya no se necesite la lista de direcciones.
Uso basico
AquΓ hay una llamada de ejemplo si usted es un servidor que desea escuchar en la direcciΓ³n IP de su host, puerto 3490. Tenga en cuenta que esto en realidad no realiza ninguna escucha ni configuraciΓ³n de red; simplemente configura estructuras que usaremos mΓ‘s adelante:
AI_PASSIVE
le dice a getaddrinfo()
que asigne la direcciΓ³n de mi host local a las estructuras de socket. Esto es conveniente porque asΓ no tienes que codificarla directamente. (O puedes colocar una direcciΓ³n especΓfica como el primer parΓ‘metro de getaddrinfo()
donde actualmente tengo NULL).
socket()
La funciΓ³n socket()
en C/C++ es una llamada al sistema que crea un nuevo socket, que es un punto de conexiΓ³n de red utilizado para la comunicaciΓ³n entre diferentes mΓ‘quinas o procesos en la misma mΓ‘quina.
Sintaxis
domain
: Especifica el dominio del socket. Puede serPF_INET
para IPv4,PF_INET6
para IPv6 oAF_UNIX
para comunicaciΓ³n local en el mismo sistema.type
: Indica el tipo de socket, comoSOCK_STREAM
para TCP (orientado a conexiΓ³n) oSOCK_DGRAM
para UDP (sin conexiΓ³n).protocol
: Generalmente se establece en0
para que el sistema seleccione el protocolo adecuado segΓΊn el tipo de socket y el dominio.
La funciΓ³n devuelve un descriptor de socket si tiene Γ©xito y -1 si ocurre un error.5
Uso basico
Lo que realmente quieres hacer es usar los valores de los resultados de la llamada a getaddrinfo() e introducirlos en socket() directamente de esta manera:
socket()
simplemente le devuelve un descriptor de socket que puede usar en llamadas posteriores al sistema, o -1 en caso de error. La variable global errno
se establece en el valor del error (consulte la pΓ‘gina de manual de errno para obtener mΓ‘s detalles y una nota rΓ‘pida sobre el uso de errno en programas multiproceso).
bind()
La funciΓ³n bind()
en C/C++ se utiliza para asociar un socket con una direcciΓ³n IP y un nΓΊmero de puerto especΓficos en el sistema local. Esto es fundamental para los servidores que esperan conexiones entrantes en un puerto especΓfico.
Sintaxis
sockfd
: El descriptor de archivo del socket que se va a asociar.addr
: Un puntero a una estructurasockaddr
que contiene la direcciΓ³n IP y el nΓΊmero de puerto.addrlen
: La longitud de la estructurasockaddr
.
La funciΓ³n bind()
en C/C++ devuelve 0 en caso de Γ©xito y -1 en caso de error.
Uso basico
Aqui tienes un ejemplo que vincula el socket al host en el que se ejecuta el programa, el puerto 3490:
A veces, es posible que notes que intentas volver a ejecutar un servidor y bind()
falla, indicando "Address already in use" (DirecciΓ³n ya en uso). ΒΏQuΓ© significa eso? Bueno, un pequeΓ±o fragmento de socket que estaba conectado todavΓa estΓ‘ presente en el kernel y estΓ‘ ocupando el puerto. Puedes esperar a que se libere (alrededor de un minuto) o agregar cΓ³digo a tu programa que le permita reutilizar el puerto, como se muestra a continuaciΓ³n:
Un pequeΓ±o detalle adicional sobre bind()
: hay momentos en los que no serΓ‘ absolutamente necesario llamarlo. Si te estΓ‘s conectando (connect()
) a una mΓ‘quina remota y no te importa quΓ© puerto local estΓ‘s utilizando (como en el caso de telnet
donde solo te importa el puerto remoto), puedes simplemente llamar a connect()
. Esta funciΓ³n verificarΓ‘ si el socket no estΓ‘ vinculado (bind()
) y lo vincularΓ‘ a un puerto local no utilizado si es necesario.
connect()
La funciΓ³n connect()
en C/C++ se utiliza para establecer una conexiΓ³n a un socket previamente creado y configurado. Esta funciΓ³n es comΓΊnmente usada en clientes para conectarse a servidores.
Sintaxis
sockfd
: El descriptor de socket que se quiere conectar.addr
: Un puntero a una estructurasockaddr
que contiene la direcciΓ³n del servidor al que se desea conectar.addrlen
: El tamaΓ±o de la estructurasockaddr
.
La funciΓ³n connect()
devuelve un valor entero. En caso de Γ©xito, devuelve 0
. Si falla, devuelve -1
y establece la variable errno
para indicar el tipo especΓfico de error que ocurriΓ³ durante la conexiΓ³n.
Uso basico
Tengamos un ejemplo en el que realizamos una conexiΓ³n de socket a "www.example.com", puerto 3490:
Listen()
La funciΓ³n listen()
en C/C++ se utiliza en servidores para esperar conexiones entrantes de clientes. DespuΓ©s de crear un socket y conectarlo a una direcciΓ³n, el servidor llama a listen()
para comenzar a escuchar conexiones entrantes, que seran hacepatadas mediante accept()
.
Sintaxis
sockfd
: El descriptor de socket que se quiere escuchar.backlog
: El nΓΊmero mΓ‘ximo de conexiones pendientes que el sistema permitirΓ‘ en la cola de espera hasta que lasaccept()
es
Nuevamente, como es habitual, listen()
devuelve -1 y establece errno
en caso de error. Devuelve 0 en caso de existo
Uso basico
Bien, como probablemente puedas imaginar, necesitamos llamar a bind()
antes de llamar a listen()
para que el servidor estΓ© ejecutΓ‘ndose en un puerto especΓfico. (Β‘Debes poder decirle a tus amigos a quΓ© puerto conectarse!) AsΓ que si vas a estar escuchando conexiones entrantes, la secuencia de llamadas al sistema que harΓ‘s es:
*DejarΓ© ese espacio como muestra de cΓ³digo, ya que es bastante autoexplicativo. (El cΓ³digo en la secciΓ³n de accept(), a continuaciΓ³n, es mΓ‘s completo). La parte realmente complicada de todo este asunto es la llamada a accept()
.llll
accept()
La funciΓ³n accept()
en C/C++ se utiliza para aceptar una conexiΓ³n entrante en un socket previamente configurado. Es especialmente importante en el lado del servidor para manejar mΓΊltiples clientes.
Lo que va a pasar es esto: alguien muy, muy lejos intentarΓ‘ connect()
a su mΓ‘quina en un puerto en el que estΓ‘ listen()
. Su conexiΓ³n estarΓ‘ en cola esperando ser accept()
. Llamas a accept()
y le dices que obtenga la conexiΓ³n pendiente.
Β‘Le devolverΓ‘ un nuevo file descriptor de archivo de socket para usar en esta ΓΊnica conexiΓ³n! AsΓ es, Β‘de repente tienes dos descriptores de archivos de socket por el precio de uno! El original todavΓa estΓ‘ escuchando mΓ‘s conexiones nuevas y el reciΓ©n creado finalmente estΓ‘ listo para send()
y recv()
.
Sintaxis
sockfd
: El descriptor de socket en el que se espera una conexiΓ³n entrante.addr
: Un puntero a una estructurasockaddr
donde se almacenarΓ‘ la direcciΓ³n del cliente.addrlen
: Un puntero a un entero sin signo que indica el tamaΓ±o de la estructurasockaddr
.
Nuevamente, como es habitual, listen()
devuelve -1 y establece errno
en caso de error. Devuelve 0 en caso de existo
Uso basico
Como antes, esto es un montΓ³n para absorber en una sola parte, asΓ que aquΓ hay un fragmento de cΓ³digo de muestra para su lectura:
Nuevamente, ten en cuenta que utilizaremos el descriptor de socket new_fd
para todas las llamadas a send()
y recv()
. Si solo esperas una ΓΊnica conexiΓ³n en todo momento, puedes cerrar el socket de escucha (sockfd
) para evitar mΓ‘s conexiones entrantes en el mismo puerto, si asΓ lo deseas.
send() and recv()
Estas dos funciones son para comunicarse a travΓ©s de sockets de flujo o sockets de datagramas conectados. Si deseas utilizar sockets de datagramas no conectados normales, deberΓ‘s consultar la secciΓ³n sobre sendto()
y recvfrom()
.
send()
La funciΓ³n send()
en C/C++ se utiliza para enviar datos a travΓ©s de un socket. Es comΓΊnmente usada en aplicaciones de red para enviar informaciΓ³n desde un cliente a un servidor o viceversa.
sockfd
: El descriptor de socket por el cual enviar los datos.buf
: Puntero al bΓΊfer que contiene los datos a enviar.len
: TamaΓ±o de los datos a enviar, en bytes.flags
: Opciones para el envΓo de datos.
send()
devuelve el nΓΊmero de bytes realmente enviados! Esto podrΓa ser menos que la cantidad que le indicaste que enviara. A veces le pides que envΓe un montΓ³n de datos y simplemente no puede manejarlo. EnviarΓ‘ tanto de los datos como pueda y confiarΓ‘ en que enviarΓ‘s el resto mΓ‘s tarde. Recuerda, si el valor devuelto por send() no coincide con el valor en len, depende de ti enviar el resto de la cadena.
En caso de error devuelve -1.
recv()
La funciΓ³n recv()
en C/C++ se utiliza para recibir datos desde un socket. Es comΓΊnmente usada en aplicaciones de red para recibir informaciΓ³n desde un cliente o servidor. Esta funciΓ³n se utiliza en el lado del receptor para leer los datos enviados por el lado del remitente.
sockfd
: El descriptor de socket desde el cual recibir los datos.buf
: Puntero al bΓΊfer donde se almacenarΓ‘n los datos recibidos.len
: TamaΓ±o mΓ‘ximo de los datos que se pueden recibir, en bytes.flags
: Opciones para la recepciΓ³n de datos.
recv()
devuelve el nΓΊmero de bytes realmente leΓdos en el bΓΊfer o -1 en caso de error (con errno establecido en consecuencia).
Β‘Espera! Β‘recv()
tambiΓ©n puede devolver 0! Esto solo puede significar una cosa: Β‘el lado remoto ha cerrado la conexiΓ³n contigo! Un valor de retorno de 0 es la forma en que recv() te indica que esto ha ocurrido.
Uso basico
Last updated