📄 socket.c
字号:
/** Javier Abellan, 20 Jun 2000** Funciones de lectura y escritura en sockets** MODIFICACIONES:* 4 Septiembre 2003: Añadidas funciones para sockets UDP.*/#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h> #include <sys/un.h>#include <netdb.h>#include <unistd.h>#include <errno.h>#include <stdio.h>#include "socket.h"/** Lee datos del socket. Supone que se le pasa un buffer con hueco * suficiente para los datos. Devuelve el numero de bytes leidos o* 0 si se cierra fichero o -1 si hay error.*/int Lee_Socket (int fd, char *Datos, int Longitud){ int Leido = 0; int Aux = 0; /* * Comprobacion de que los parametros de entrada son correctos */ if ((fd == -1) || (Datos == NULL) || (Longitud < 1)) return -1; /* * Mientras no hayamos leido todos los datos solicitados */ while (Leido < Longitud) { Aux = read (fd, Datos + Leido, Longitud - Leido); if (Aux > 0) { /* * Si hemos conseguido leer datos, incrementamos la variable * que contiene los datos leidos hasta el momento */ Leido = Leido + Aux; } else { /* * Si read devuelve 0, es que se ha cerrado el socket. Devolvemos * los caracteres leidos hasta ese momento */ if (Aux == 0) return Leido; if (Aux == -1) { /* * En caso de error, la variable errno nos indica el tipo * de error. * El error EINTR se produce si ha habido alguna * interrupcion del sistema antes de leer ningun dato. No * es un error realmente. * El error EGAIN significa que el socket no esta disponible * de momento, que lo intentemos dentro de un rato. * Ambos errores se tratan con una espera de 100 microsegundos * y se vuelve a intentar. * El resto de los posibles errores provocan que salgamos de * la funcion con error. */ switch (errno) { case EINTR: case EAGAIN: usleep (100); break; default: return -1; } } } } /* * Se devuelve el total de los caracteres leidos */ return Leido;}/** Escribe dato en el socket cliente. Devuelve numero de bytes escritos,* o -1 si hay error.*/int Escribe_Socket (int fd, char *Datos, int Longitud){ int Escrito = 0; int Aux = 0; /* * Comprobacion de los parametros de entrada */ if ((fd == -1) || (Datos == NULL) || (Longitud < 1)) return -1; /* * Bucle hasta que hayamos escrito todos los caracteres que nos han * indicado. */ while (Escrito < Longitud) { Aux = write (fd, Datos + Escrito, Longitud - Escrito); if (Aux > 0) { /* * Si hemos conseguido escribir caracteres, se actualiza la * variable Escrito */ Escrito = Escrito + Aux; } else { /* * Si se ha cerrado el socket, devolvemos el numero de caracteres * leidos. * Si ha habido error, devolvemos -1 */ if (Aux == 0) return Escrito; else return -1; } } /* * Devolvemos el total de caracteres leidos */ return Escrito;}/** * Lee un mensaje de un socket udp. Los parametros que se pasan son: * - Descriptor fd del socket del que se quiere leer. * - Estructura Remoto, en la que se devolvera los datos del que ha enviado el * mensaje que acabamos de leer. * - Longitud_Remoto de la estructura anterior. Debe pasarse relleno con el tamaño * de Remoto y se devolvera rellena con el tamaño de los datos en Remoto. * - Buffer de Datos donde se quiere que aparezca el mensaje. * - Longitud_Datos del buffer anterior. * * Devuelve el numero de bytes leidos o -1 en caso de error. */int Lee_Socket_Udp ( int fd, struct sockaddr *Remoto, socklen_t *Longitud_Remoto, char *Datos, int Longitud_Datos){ int Leido = 0; int Aux = 0; /* * Comprobacion de que los parametros de entrada son correctos */ if ((fd == -1) || (Datos == NULL) || (Longitud_Datos < 1) || (Remoto == NULL) || (Longitud_Remoto == NULL)) { return -1; } /* * Mientras no hayamos leido todos los datos solicitados */ while (Leido < Longitud_Datos) { Aux = recvfrom (fd, Datos + Leido, Longitud_Datos - Leido, 0, Remoto, Longitud_Remoto); if (Aux > 0) { /* * Si hemos conseguido leer datos, incrementamos la variable * que contiene los datos leidos hasta el momento */ Leido = Leido + Aux; } else { /* * Si read devuelve 0, es que se ha cerrado el socket. Devolvemos * los caracteres leidos hasta ese momento */ if (Aux == 0) return Leido; if (Aux == -1) { /* * En caso de error, la variable errno nos indica el tipo * de error. * El error EINTR se produce si ha habido alguna * interrupcion del sistema antes de leer ningun dato. No * es un error realmente. * El error EGAIN significa que el socket no esta disponible * de momento, que lo intentemos dentro de un rato. * Ambos errores se tratan con una espera de 100 microsegundos * y se vuelve a intentar. * El resto de los posibles errores provocan que salgamos de * la funcion con error. */ switch (errno) { case EINTR: case EAGAIN: usleep (100); break; default: return -1; } } } } /* * Se devuelve el total de los caracteres leidos */ return Leido;}/*** Escribe dato en el socket cliente. Devuelve numero de bytes escritos,* o -1 si hay error.* - fd es el descriptor del socket.* - Remoto es el destinatario del mensaje, a quien se lo queremos enviar. * - Longitud_Remoto es el tamaño de Remoto en bytes.* - Datos es el mensaje que queremos enviar.* - Longitud_Datos es el tamaño del mensaje en bytes.*/int Escribe_Socket_Udp (int fd, struct sockaddr *Remoto, socklen_t Longitud_Remoto, char *Datos, int Longitud_Datos){ int Escrito = 0; int Aux = 0; /* * Comprobacion de los parametros de entrada */ if ((fd == -1) || (Datos == NULL) || (Longitud_Datos < 1) || (Remoto == NULL) ) { return -1; } /* * Bucle hasta que hayamos escrito todos los caracteres que nos han * indicado. */ while (Escrito < Longitud_Datos) { Aux = sendto (fd, Datos + Escrito, Longitud_Datos - Escrito, 0, Remoto, Longitud_Remoto); if (Aux > 0) { /* * Si hemos conseguido escribir caracteres, se actualiza la * variable Escrito */ Escrito = Escrito + Aux; } else { /* * Si se ha cerrado el socket, devolvemos el numero de caracteres * leidos. * Si ha habido error, devolvemos -1 */ if (Aux == 0) return Escrito; else { return -1; } } } /* * Devolvemos el total de caracteres leidos */ return Escrito;}/** * Rellena una estructura sockaddr_in con los datos que se le pasan. Esta estrutura es * util para el envio o recepcion de mensajes por sockets Udp o para abrir conexiones. * Se le pasa el host. Puede ser NULL (para abrir socket servidor Udp o para recepcion de * mensajes de cualquier host). * Se le pasa el servicio. Puede ser NULL (para abrir socket cliente Udp). * Se le pasa una estructura sockaddr_in que devolvera rellena. * Se le pasa una Longitud. Debe contener el tamaño de la estructura sockaddr_in y * devolvera el tamaño de la estructura una vez rellena. * Devuelve -1 en caso de error. */int Dame_Direccion_Udp (char *Host, char *Servicio, struct sockaddr_in *Servidor, int *Longitud_Servidor){ struct servent *Puerto; struct hostent *Maquina; /* Comprobacion de parametros */ if (Servidor == NULL) return -1; /* Relleno del primer campo de la estructura */ Servidor->sin_family = AF_INET; /* Si nos han pasado un host ... */ if (Host != NULL) { /* ... obtenemos la direccion del host y la ponemos en la estructura */ Maquina = gethostbyname (Host); if (Maquina == NULL) return -1; Servidor->sin_addr.s_addr = ((struct in_addr *)(Maquina->h_addr))->s_addr; } else /* Si no nos han pasado un host, ponemos cualquier host. */ Servidor->sin_addr.s_addr = INADDR_ANY; /* Si servicio en NULL, hacemos que el puerto lo eliga el sistema operativo libremente.*/ if (Servicio == NULL) Servidor->sin_port = 0; else { /* Si el servicio no es NULL, lo obtenemos. */ Puerto = getservbyname (Servicio, "udp"); if (Puerto == NULL) return -1; Servidor->sin_port = Puerto->s_port; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -