Programación con sockets I Aplicaciones cliente/servidor sobre TCP/IP Aplicaciones API SOCKET UDP TCP UDP TCP Puerto (16 bits) IP IP Dirección (32 bits) cliente Red servidor Aplicaciones cliente/servidor sobre TCP/IP Dirección IP: localiza un interface de red de ordenador en Internet. Puerto: identifica las aplicaciones dentro del ordenador, puede utilizar los protocolos de transporte TCP (orientado a conexión) o UDP (no orientado a conexión). Una asociación se define por: Dirección IP cliente. Puerto cliente. Dirección IP servidor. Puerto servidor. Protocolo de transporte: TCP o UDP. Una comunicación está definida por una asociación. Si cambia un solo parámetro, es otra asociación distinta: <193.146.9.1, 1500, 193.146.9.34, 1800, UDP> <193.146.9.1, 1501, 193.146.9.34, 1800, UDP> <193.146.9.1, 1502, 193.146.9.34, 1800, UDP> Esquema de aplicación con UDP Socket() bind() recvfrom() Espera socket() sendto() Procesado de la petición sendto() recvfrom() Espera close() close() Dominio de direcciones •Estructura genérica de una dirección (utilizada en las llamadas a las funciones): struct sockaddr { u_short sa_family; /* familia de la dirección, 2 bytes */ char sa_data[14]; /* 14 bytes de dirección como máximo*/ }; •Estructura particular del dominio Internet (utilizada en Internet): AF_INET struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; /* debe valer AF_INET, 2 bytes */ /* número de puerto, 2 bytes */ /* dirección Internet , 4 bytes */ /* campo de 8 bytes ceros, no usada */ struct in_addr { u_long s_addr; /* dirección IP 32 bits, en formato de red */ }; Funciones de conversión Hay 4 tipos de funciones de conversión: unsigned long htonl (x) /* host to network long */ unsigned long x; unsigned short htons(x) /* host to network short */ unsigned short x; unsigned long ntohl(x) /* network to host long */ unsigned long x; unsigned short ntohs(x) /* network to host short */ unsigned short x; Se utiliza htohs() para convertir el puerto. Funciones de conversión Traducir una dirección IP en ASCII en notación punto “aaa.bbb.ccc.ddd” a formato de red. unsigned long inet_addr(char *ptr); Traducir una dirección IP en formato de red a una dirección en ASCII notación punto. char* inet_ntoa(struct inaddr) Necesitamos añadir los siguientes includes: #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> Otras funciones Rellenar con ceros una estructura: bzero(char *adr, int lg) Utilidad: inicializar la estructutra de la dirección. struct sockaddr_in dir_cli; /* declaración */ bzero ((char*) &dir_cli, sizeof (dir_cli)); Tratamiento de errores: utilizada para tratar el resultado de las llamadas de sockets. If (n < 0) error(“error en sendto\n”); void error(char *mesg) { perror(mesg); exit (1); } Completar información de dirección. Es necesario completar la dirección del destinatario del mensaje: #define SERVER “172.29.20.5” #define SERVER_PORT “6500” struct sockaddr_in server; /*declaración*/ bzero((char *) &server, sizeof(server));/*poner a cero*/ /*inicializa dirección y puerto*/ server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr(SERVER); server.sin_port = htons(SERVER_PORT); Creación de socket Includes necesarios utilizar las llamadas a sockets: #include <sys/types.h> #include <sys/socket.h> Crea un descriptor de socket. Sintaxis: int socket(int dominio,int tipo,int protocolo) Ejemplo: sockfd = socket(AF_INET, SOCK_DGRAM,0); Devuelve un identificador del socket que utilizaremos en el resto de operaciones. Devuelve -1 si error. Enlace de socket Enlaza el socket con una dirección y puerto local indicados. Sintaxis: int bind(int desc, struct sockaddr * p_direccion, int long) Ejemplo: struct sockaddr_in server; /* rellenar la estructura*/ bind(sockfd, (struct sockaddr*)&server, sizeof(server)); Si se produce error devuelve -1. Es obligatoria en el servidor para forzar a escuchar en un puerto determinado. Si no se utiliza, el sistema utiliza un puerto libre (válido en el cliente). En el cliente no es obligatorio pero si se hace: •Si hacemos client.sin_port=0 el sistema asignará un puerto libre local libre. •Si hacemos client.sin_addr = INADDR_ANY el sistema Asigna la dirección del propio interfaz. Enviar datos Sintaxis: int sendto(desc, msg, lg, opcion, p_dest, lg_dest) int desc; /* descriptor del socket de emisión */ char* msg; /* mensaje a enviar */ int lg; /* longitud del mensaje */ int opcion; /* 0 */ struct sockaddr *p_dest; /* puntero a la dirección del socket destino */ int lg_dest; /* longitud de la dirección del socket destino */ Devuelve la longitud de los datos transmitidos en bytes o -1 si ha habido error. Ejemplo: int n; n = sendto(sockfd,(char *) &datos, sizeof(datos),0, (struct sockaddr *) &server, sizeof(server)); Recibir datos Sintaxis: int recvfrom(desc, msg, lg, opcion, p_exp, p_lgexp) int desc; /* descriptor del socket de recepción */ char *msg; /* buffer para el mensaje */ int lg; /* tamaño del buffer */ int opcion; /* 0 normalmente, MSG_PEEK */ struct sockaddr *p_exp; /* recupera la dirección del remitente */ int *p_lgexp; /* longitud de p_exp*/ Llamada bloqueante. La variable p_lgexp hay que inicializarla antes de llamar a recvform(). Devuelve la cantidad de bytes recibidos o -1 si hay error. Ejemplo: int ld = sizeof (client); recvfrom(sockfd, (char *)&datos, sizeof(datos), 0, (struct sockaddr *) &dir_cli, &ld ); Cerrar socket Cerrar socket. Sintaxis: close(int desc); /*se pasa el descriptor de socket*/