Funciones Importantes

En esta sección, (en la cual se nombrarán algunas de las funciones más utilizadas para la programación en C de sockets), se mostrará la sintaxis de la función, las bibliotecas necesarias a incluir para llamarla, y algunos pequeños comentarios. Además de las que se mencionan aquí, existen muchas funciones más, aunque sólo decidí incluir éstas. Tal vez sean incluidas en una futura versión de este documento[1]. Nuevamente, para ver ejemplos sobre el uso de estas funciones, se podrá leer la sección de nombre Un ejemplo de Servidor de Flujos y la sección de nombre Un ejemplo de Cliente de Flujos, en las cuales hay código fuente de un Cliente de Flujos y un Servidor de Flujos.

socket()

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

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

Analicemos los argumentos:

La función socket() nos devuelve un descriptor de socket, el cual podremos usar luego para llamadas al sistema. Si nos devuelve -1, se ha producido un error (obsérvese que esto puede resultar útil para rutinas de verificación de errores).

bind()

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

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

Analicemos los argumentos:

La llamada bind() se usa cuando los puertos locales de nuestra máquina están en nuestros planes (usualmente cuando utilizamos la llamada listen()). Su función esencial es asociar un socket con un puerto (de nuestra máquina). Análogamente socket(), devolverá -1 en caso de error.

Por otro lado podremos hacer que nuestra dirección IP y puerto sean elegidos automáticamente:

    
      server.sin_port = 0;                 /* bind() elegirá un puerto aleatoriamente */
      server.sin_addr.s_addr = INADDR_ANY; /* pone la Ip del seridor automáticamente  */
    
      

Un aspecto importante sobre los puertos y la llamada bind() es que todos los puertos menores que 1024 están reservados. Se podrá establecer un puerto, siempre que esté entre 1024 y 65535 (y siempre que no estén siendo usados por otros programas).

connect()

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

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

Analicemos los argumentos:

La función connect() se usa para conectarse a un puerto definido en una dirección IP. Devolverá -1 si ocurre algún error.

listen()

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

int listen(int fd,int backlog); 
 
      

Veamos los argumentos de listen():

La función listen() se usa si se están esperando conexiones entrantes, lo cual significa, si se quiere, que alguien pueda conectarse a nuestra máquina.

Después de llamar a listen(), se deberá llamar a accept(), para así aceptar las conexiones entrantes. La secuencia resumida de llamadas al sistema es:

  1. socket()

  2. bind()

  3. listen()

  4. accept()/* En la próxima sección se explicará como usar esta llamada */

Como todas las funciones descritas arriba, listen() devolverá -1 en caso de error.

accept()

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

int accept(int fd, void *addr, int *addrlen);
      

Veamos los argumentos de la función:

Cuando alguien intenta conectarse a nuestra computadora, se debe usar accept() para conseguir la conexión. Es muy fácil de entender: alguien sólo podrá conectarse (asóciese con connect()) a nuestra máquina, si nosotros aceptamos (asóciese con accept()) ;-)

A continuación, Se dará un pequeño ejemplo del uso de accept() para obtener la conexión, ya que esta llamada es un poco diferente de las demás.

      
(...)

sin_size=sizeof(struct sockaddr_in);
/* En la siguiente línea se llama a accept() */ 
if ((fd2 = accept(fd,(struct sockaddr *)&client,&sin_size))==-1){ 
printf("accept() error\n");
exit(-1);
}

(...)

A este punto se usará la variable fd2 para añadir las llamadas send() y recv().

send()

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

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

Y sobre los argumentos de esta llamada:

El propósito de esta función es enviar datos usando sockets de flujo o sockets conectados de datagramas. Si se desea enviar datos usando sockets no conectados de datagramas debe usarse la llamada sendto(). Al igual que todas las demás llamadas que aquí se vieron, send() devuelve -1 en caso de error, o el número de bytes enviados en caso de éxito.

recv()

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

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

Veamos los argumentos:

Al igual de lo que se dijo para send(), esta función es usada con datos en sockets de flujo o sockets conectados de datagramas. Si se deseara enviar, o en este caso, recibir datos usando sockets desconectados de Datagramas, se debe usar la llamada recvfrom(). Análogamente a send(), recv() devuelve el número de bytes leídos en el búfer, o -1 si se produjo un error.

recvfrom()

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

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

Veamos los argumentos:

Análogamente a lo que pasaba con recv(), recvfrom() devuelve el número de bytes recibidos, o -1 en caso de error.

close()

#include <unistd.h>

close(fd);

La función close() es usada para cerrar la conexión de nuestro descriptor de socket. Si llamamos a close() no se podrá escribir o leer usando ese socket, y si alguien trata de hacerlo recibirá un mensaje de error.

shutdown()

  
#include <sys/socket.h>

int shutdown(int fd, int how);

Veamos los argumentos:

Es lo mismo llamar a close() que establecer how a 2. shutdown() devolverá 0 si todo ocurre bien, o -1 en caso de error.

gethostname()

#include <unistd.h>

int gethostname(char *hostname, size_t size);

Veamos de qué se tratan los argumentos:

La función gethostname() es usada para obtener el nombre de la máquina local.

Notas

[1]

Se puede indagar más sobre éstas y las demás funciones relacionadas con Sockets en UNIX, leyendo las páginas de manual correspondientes a cada una. Nota del Traductor.

[2]

El argumento ``flags'', también contenido en otras funciones de manejo de sockets, no es una característica propia del mensaje, y puede omitirse. En este caso, hace distinción entre los modos de enviar un paquete, además de otras cosas. Para más información, se puede leer el manual de send() (man 2 send). Nota del T.