7.4 La aplicación send

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.

7.4.1 send.c

/******************************************************************************  
 * 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));  
  }  
 
}