La aplicación send funciona básicamente como un pipe, copiando la entrada estándar a la salida estándar, sin realizar ningún tipo de procesamiento. Simultaneamente, emite una secuencia de paquetes a una dirección IP destino que puede ser la dirección de un canal multicast. También puede especificarse un puerto destino.
/******************************************************************************
* send.c -- Emisor de datos a través de UDP. * * Envía una copia de la entrada estándar hacia una dirección IP * usando el protocolo UDP. La entrada es tambíen copiada a la salida * estándar. * * gse. 2005. *****************************************************************************/ /****************************************************************************** * * Ficheros cabecera. * *****************************************************************************/ /* Entrada y salida de streams buffereados. */ #include <stdio.h> /* Biblioteca de funciones estándar (exit(), EXIT_SUCCESS, EXIT_FAILURE, ...) */ #include <stdlib.h> /* Manipulación de cadenas y movimiento de memoria (memset(), ...). */ #include <string.h> /* Biblioteca estándar de funciones relacionadas con el sistema operativo Unix (read(), write(), getopt(), ...). */ #include <unistd.h> #include <fcntl.h> /* Sockets. */ /* Más info en: * * http://www.csce.uark.edu/~aapon/courses/os/examples/concurrentserver.c * http://www.fortunecity.com/skyscraper/arpanet/6/cc.htm * http://beej.us/guide/bgnet/ */ /* Tipos de datos primitivos del sistema. */ #include <sys/types.h> /* Sockets (socket(), listen(), ...). */ #include <sys/socket.h> /* Direcciones IP, opciones y definiciones. */ #include <netinet/in.h> /* Servicio de resolución de nombres. */ #include <netdb.h> /* Signals (interrupciones) (signal(), SIGINT). */ #include <signal.h> /****************************************************************************** * * Definiciones. * *****************************************************************************/ /* Número de bytes del buffer de audio. */ #define BUFFER_SIZE 512 /* Puerto destino de los datagramas. */ #define SOCKET_PORT 6666 /* TTL por defecto. 1 -> que el datagrama no saldrá de la red local. */ #define DEFAULT_TTL 1 /****************************************************************************** * * Variable globales. * *****************************************************************************/ int sd; /* Socket descriptor */ /****************************************************************************** * * Funciones. * *****************************************************************************/ /* Cuerpo principal del programa. */ int main(int argc, char *argv[]) { work(argc, argv); return EXIT_SUCCESS; } work(int argc, char *argv[]) { /* Si pulsamos CRTL+C, el programa acaba ejecutando la función end(). */ void end() { fprintf(stderr,"%s: CTRL+C detected. Exiting ... ",argv[0]); close(sd); fprintf(stderr,"done\n"); exit(EXIT_SUCCESS); } signal(SIGINT, end); //activando la senal SIGINT /* Tamaño del buffer. */ int buffer_size = BUFFER_SIZE; /* Dirección destino por defecto de los datagramas. */ char *destination_hostname = "localhost"; /* Puerto destino por defecto de los datagramas. */ int destination_port = SOCKET_PORT; /* TTL del datagrama. Controla lo lejos que llega. */ unsigned char ttl = DEFAULT_TTL; int c; while ((c = getopt (argc, argv, "b:h:p:t:")) != -1) { switch (c) { case ’b’: buffer_size = atoi(optarg); break; case ’h’: destination_hostname = optarg; break; case ’p’: destination_port = atoi(optarg); break; case ’t’: ttl = atoi(optarg); break; case ’?’: if (isprint (optopt)) fprintf (stderr, "Unknown option ‘-%c’.\n", optopt); else fprintf (stderr, "Unknown option character ‘\\x%x’.\n", optopt); return 1; default: abort (); } } fprintf(stderr,"%s: buffer size = \"%d\"\n", argv[0],buffer_size); fprintf(stderr,"%s: destination hostname = \"%s\"\n", argv[0],destination_hostname); fprintf(stderr,"%s: destination port = \"%d\"\n", argv[0],destination_port); fprintf(stderr,"%s: TTL = \"%d\"\n", argv[0],ttl); /* Preguntamos al DNS por la dir IP destino */ struct hostent *destination_IP; if ((destination_IP=gethostbyname(destination_hostname)) == NULL) { perror("gethostbyname"); exit(EXIT_FAILURE); } /* Creamos el socket UDP no bloqueante. El socket es no bloqueante con el objetivo de no interrumpir el pipe de audio si la red se congestiona. */ if((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); exit(EXIT_FAILURE); } fcntl(sd, F_SETFL, O_NONBLOCK); /* Sin esto, el socket es bloqueante */ /* Dir IP y puerto del socket. */ struct sockaddr_in socket_addr; { /* Usaremos Internet */ socket_addr.sin_family = AF_INET; /* IP destino de los datagramas */ socket_addr.sin_addr = *((struct in_addr *)destination_IP->h_addr); /* Puerto destino de los datagramas */ socket_addr.sin_port = htons(destination_port); memset(&(socket_addr.sin_zero), ’\0’, 8); } /* Actualizamos el TTL del datagrama. */ setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); char *buffer = (char *)malloc(buffer_size*sizeof(char)); for(;;) { /* Buffer con el audio */ //char buffer[BUFFER_SIZE]; /* Leémos la stdin */ int bytes_read = read(0, (void *)buffer, buffer_size); /* Escribimos la stdout */ write(1, (void *)buffer, bytes_read); /* Enviamos el datagrama */ sendto(sd, (void *)buffer, bytes_read, 0, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr)); } } |