47
1 Universidad Autónoma Metropolitana Unidad Iztapalapa División de Ciencias Básicas e Ingeniería Departamento de Ingeniería Eléctrica Licenciatura en Computación __________________________________________________ Proyecto de Investigación I y II Propuesta de un sistema que permita la interacción entre dos máquinas mediante el juego de ping-pong Asesora: Graciela Román Alonso Alumno: Adrián Alfonso Alcántara Valencia Matrícula: 204213958

Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

  • Upload
    vanthuy

  • View
    219

  • Download
    3

Embed Size (px)

Citation preview

Page 1: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

1

Universidad Autónoma Metropolitana Unidad Iztapalapa

División de Ciencias Básicas e Ingeniería

Departamento de Ingeniería Eléctrica

Licenciatura en Computación

__________________________________________________

Proyecto de Investigación I y II

Propuesta de un sistema que permita la interacción entre dos máquinas mediante el juego de ping-pong

Asesora: Graciela Román Alonso

Alumno: Adrián Alfonso Alcántara Valencia

Matrícula: 204213958

Page 2: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

2

Índice

1 Introducción 3 2 Objetivos 3 3 Redes inalámbricas de datos 3 3.1 Red de Internet casera con un Gateway/Router residencial 4 3.2 Red de Internet casera con las direcciones IP múltiples 4 3.3 Red “Ad Hoc” 4 3.4 Red “Ad Hoc” que comparte el acceso a Internet 4 3.5 Red WIFI de Infraestructura 5 4 Toma de decisiones 5 4.1 ¿Qué clase de red es la mejor para nosotros? 5 4.2 ¿Porqué elegir una red inalámbrica 5 4.3 Diferencias ante una red cableada convencional? 5 5 Instalación de una red “Ad Hoc” 6 5.1 Algunos lineamientos de las direcciones IP 6 6 Ping 8 7 SSH (Secure SHell) 9 7.1 Creación de llave publica 10 8 SFTP (Secure File Transfer Protocol) 10 9 Protocolos de comunicación 11 9.1 Protocolos UDP (User Datagram Protocol) 11 9.2 Socket UDP 11 9.2.1 Servidor 12 9.2.2 Cliente 13 9.2.3 Servidor 15 9.2.4 Cliente 16 9.3 MPI (Interfaz de Paso de Mensajes) 20 9.4 Socket UDP vs MPI (Interfaz de Paso de Mensajes) 23 10 Interfaz gráfica 24 10.1 GTK+ 24 10.2 Ncurses 29 10.3 Cairo 31 11 Con visión al resultado 32 11.1 Servidor 36 11.2 Cliente 41 12 Conclusiones 47 13 Referencias virtuales 47

Page 3: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

3

1. Introducción

Actualmente los sistemas distribuidos son una tecnología que es cada vez más utilizada en el desarrollo de aplicaciones. El tener las bases para implementar protocolos de comunicación y sincronización entre dos o más computadoras abre el panorama de diseño de aplicaciones en diferentes ámbitos de la vida diaria.

En este proyecto, se pretende adquirir las bases proponiendo un sistema distribuido plasmado mediante un

juego de ping-pong entre dos computadoras que involucran interfaces gráficas y desarrollo de protocolos de comunicación.

La realización de este proyecto exige comunicar a las computadoras de alguna forma. Los requerimientos

de la forma en que van a operar los equipos no exige una centralización en la administración de las tareas, pero si, una sincronización de procesos. Este hecho seria en función de la aplicación a ocupar y las herramientas involucradas en la ejecución.

Para comunicar los equipos, se necesita implementar una red. Cualquier equipo puede operar como

servidor y cliente a la vez en la ejecución de las tareas. Dadas las condiciones, nos daremos a la tarea de investigar que tipo de red utilizaremos.

2. Objetivos

- Construir una aplicación distribuida en el que dos máquinas entablen una comunicación interactiva.

- Proponer una interfaz gráfica para simular el comportamiento de una pelota de ping-pong.

3. Redes Inalámbricas de datos

Una de las tecnologías más prometedoras y discutidas en esta década es la de poder comunicar computadoras mediante tecnología inalámbrica. Esta tecnología, está surgiendo como una solución alternativa para los desarrollos empresariales, públicos y residenciales. Ahora dicha tecnología está desconectando al Internet, vinculando nuestras máquinas y cambiando la manera de como nos comunicamos.

La tecnología inalámbrica es un sistema de comunicación de datos flexible muy utilizado como alternativa a la LAN cableada o como una extensión de ésta. Se comunica a través de medios de transmisión no guiados, envía señales de radio por medio de una antena y luego se reciben estas con otra antena.

Algunas de las ventajas que nos permite conectar nuestros equipos a través de una red son:

Compartir la conexión a Internet de alta velocidad Compartir música, imágenes, archivos y otros recursos Ejecución de aplicaciones en línea

Page 4: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

4

Para comenzar, seleccionemos el tipo de red inalámbrica que instalaremos.

3.1. Red de Internet casera con un Gateway/Router residencial

Ideal si nosotros tenemos dos o más computadoras (computadoras portátiles o de escritorio) y deseamos compartir archivos, y el acceso del Internet usando un Gateway/Router residencial con DHCP o conectar con una red de Ethernet que utilice direcciones IP dinámicas (DHCP).

Requisitos: Un Gateway/Router residencial conectado con un cable de Ethernet (CAT5) con un punto de acceso 802.11a/b o un punto de acceso 802.11a/g u otra computadora con una tarjeta de 802.11b/g WLAN instalada.

3.2. Red de Internet casera con las direcciones IP múltiples

Si nosotros tenemos dos o más computadoras (computadoras portátiles o de escritorio) y deseamos compartir el acceso del Internet con una red de Ethernet que utiliza una dirección IP estática.

Este tipo de instalación requiere que su ISP (Internet Service Provider) le proporcione una dirección IP estática para cada computadora y para el punto de acceso en su red.

3.3. Red “Ad Hoc”

Ideal si nosotros tenemos dos o más computadoras (de escritorio o computadoras portátiles) y deseamos compartir archivos, pero no tenemos ninguna conexión de Internet.

Requisitos: Tarjetas inalámbricas de red, por ejemplo, el adaptador inalámbrico de red 802.11g Cardbus PCMCIA o PCI.

3.4. Red “Ad Hoc” que comparte el acceso a Internet

Si nosotros tenemos dos o más computadoras (de escritorio o las computadoras portátiles), y deseamos compartir aplicaciones y el acceso a Internet usando una computadora de escritorio o una computadora portátil como servidor del Internet,

Para compartir una conexión del Internet nosotros necesitamos comprar el software (por ejemplo Wingate), o la utilidad (ICS) proporcionada por Windows XP, Windows 2000, Windows YO o Windows 98SE.

Page 5: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

5

3.5. Red WIFI de Infraestructura

Esta arquitectura se basa en 2 elementos: uno, o más Puntos de Acceso y Estaciones Cliente (fijas o móviles), que se conectan al servidor a través del Punto de Acceso.

4. Toma de decisiones

4.1. ¿Qué clase de red es la mejor para nosotros?

En gran medida, la tecnología de redes de cables más común hoy en día se conoce como Ethernet. Los cables de datos, conocidos como los cables de red Ethernet o cables CAT5, conectan las computadoras y otros dispositivos para formar redes.

Las redes inalámbricas son relativamente nuevas. No utilizan los cables para las conexiones. En su lugar, utilizan las ondas de radio, como los teléfonos celulares.

4.2. ¿Porqué elegir una red inalámbrica?

Libertad - trabajar en donde se requiera Instalación rápida, sin esfuerzo No hay que comprar ningún cable Se amplían fácilmente

4.3. Diferencias ante una red cableada convencional

Un costo de instalación relativamente más caro si no se cuentan con los dispositivos necesarios. Son menos rápidas, las redes cableadas convencionales alcanzan una velocidad de hasta 1000Mbps Un rango de alcance posiblemente menor. La distancia entre los dispositivos conectados en una red convencional, también esta menos limitada: hasta

90 metros con cables Ethernet Cat5 o 584 metros usando fibra óptica. Cuando nosotros necesitamos mover cantidades grandes de datos a altas velocidades, tales como archivos multimedia de calidad profesional, las redes cableadas son la manera más eficiente de hacerlo

Una gran ventaja de las redes inalámbricas:

Las redes inalámbricas pueden interconectar computadoras separadas por una distancia de hasta 10 km. mediante la instalación de antenas externas polarizadas de alta ganancia (11 dBi o mas).

Nosotros contamos con equipos tablet-PC, que están dotados de una arquitectura de doble núcleo y los dispositivos necesarios para una fácil y dinámica conexión inalámbrica, no contamos con un router, un punto de acceso, o un ISP.

No necesitamos por el momento, dado los alcances que se pretenden en el proyecto, una conexión a Internet. De acuerdo a las condiciones y nuestros recursos, hemos optado por implementar una red “Ad Hoc”.

Nuestros equipos ya tienen configurado la tarjeta inalámbrica, para consultar sobre el tema, se puede

consultar el punto [1] y [2] de las referencias virtuales.

Page 6: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

6

5. Instalación de una red “Ad Hoc” Nosotros instalaremos nuestra red en Linux, para ello, realizaremos los siguientes pasos: Para montar una red por comando de línea, realizaremos los siguientes pasos:

En el equipo 1 ejecutamos las siguientes líneas:

usr@user-laptop:~$iwconfig eth1 mode Ad-Hoc essid PROY1 channel 11 ifconfig eth1 192.168.100.2

En el equipo 2, ponemos exactamente lo mismo, teniendo cuidado al respetar, los lineamientos de las direcciones IP.

usr@user-laptop:~$iwconfig eth1 mode Ad-Hoc essid PROY1 channel 11 ifconfig eth1 192.168.100.3

Con estos dos pasos ya tenemos montada una red Ad-Hoc. Podemos cambiar el número del canal, PROY1 es el nombre de la red, para mayor información, podemos consultar la referencia [5].

Hablemos un poco de los lineamientos de las direcciones IP, solo los suficientes para implementar nuestra red.

5.1. Algunos lineamientos de las direcciones IP

Las direcciones IP se pueden expresar como números de notación decimal: se dividen los 32 bits de la dirección en cuatro octetos. El valor decimal de cada octeto puede ser entre 0 y 255 [el número binario de 8 bits más alto es 11111111 y esos bits, de derecha a izquierda, tienen valores decimales de 1, 2, 4, 8, 16, 32, 64 y 128, lo que suma 256 en total, 255 más la 0 (0000 0000)].

En la expresión de direcciones IPv4 en decimal se separa cada octeto por un carácter único ".". Cada uno de estos octetos puede estar comprendido entre 0 y 255, salvo algunas excepciones. Los ceros iníciales, si los hubiera, se pueden obviar (010.128.001.255 sería 10.128.1.255).

Ejemplo de representación de dirección IPv4: 164.12.123.65

1- En la realización de este proyecto, utilizaremos direcciones versión 4 del Protocolo IP (IPv4). 2- Las direcciones IP no pueden repetirse. 3- Hay 2 direcciones IP que están reservadas, las direcciones de este tipo: x.x.x.0 y x.x.x.255, donde x

-> [0,255], ya que las direcciones que terminan en 0, son el identificador de la red, y las que terminan en 255, son la dirección que se utiliza como broadcast dentro de una red.

4- Hay que tener cuidado al definir nuestras direcciones TCP/IP dentro de la red, cuando asignemos una dirección, debe de prevalecer en el entorno de red.

5- Principalmente hay 5 clases de direcciones IP, nosotros implementaremos nuestra red en no mas de 254 equipos, por lo tanto, nos servirá utilizar una red de clase C, hablemos un poco de ello:

En una red de clase C, se asignan los tres primeros octetos para identificar la red, reservando el octeto final (8 bits) para que sea asignado a los hosts, de modo que la cantidad máxima de hosts es 28 - 2, ó 254 hosts.

Otra forma de instalar la red, es en modo gráfico, los pasos a seguir para instalar una red sobre equipos con Sistema Operativo Fedora son:

Page 7: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

7

Dar click izquierdo sobre el icono de conexiones de red.

Seleccionar la opción crear una red inalámbrica nueva.

Le asignamos un nombre a nuestra red (PROY1), y el tipo de seguridad que le brindaremos, en este caso, permitiremos por el momento, el acceso libre a la red.

Ahora, editaremos las conexiones, es decir, sobre el icono de conexiones de red, le daremos click derecho para configurar nuestra dirección IP.

Elegimos la pestaña de conexión inalámbrica, y a continuación, la red que acabamos de crear.

Será una conexión de tipo Ad-hoc, y en Ajustes de Ipv4, seleccionaremos la opción del método manual, para asignarle una dirección estática, le damos click en la opción añadir, y procedemos a asignar una dirección, en este caso, será:

IP: 192.168.10.112

Mascara de red: 255.255.255.0

Page 8: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

8

No nos preocuparemos por los servidores DNS y los dominios de búsqueda.

Haciendo un ping sobre nuestra dirección IP, nos podremos dar cuenta que instalamos correctamente nuestra red, en los demás equipos, tenemos que realizar los mismos pasos, asignándoles una dirección IP, dentro del rango 192.168.10.1 y 192.168.10.254, con la excepción de la dirección 192.168.10.111. La dirección 192.168.10.0 corresponde al identificador de la red y la dirección 192.168.10.255 es la dirección de broadcast.

Para la instalación de una red en Windows, podemos revisar el enlace [6].

Ya que tenemos nuestras maquinas conectadas en línea, existe una herramienta muy buena, que nos permite trabajar sobre el otro equipo, esta herramienta es SSH.

6. Ping

El comando ping comprueba el estado de la conexión con uno o varios equipos remotos por medio de los paquetes de solicitud de eco y de respuesta de eco (ambos definidos en el protocolo de red ICMP) para determinar si un sistema IP específico es accesible en una red. Es útil para diagnosticar los errores en redes o enruteadores IP.

En esta imagen, podemos observar que se esta haciendo ping sobre el equipo con dirección IP 192.168.10.112 y 192.168.10.111 respectivamente, en los 2 casos, se transmitieron 4 paquetes de prueba en cada ocasión, con un 0% de porcentaje de pérdida en la recepción, es decir, la comunicación entre nuestros equipos, es excelente.

Page 9: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

9

7. SSH (Secure SHell)

Intérprete de órdenes seguras. Es el nombre de un protocolo y del programa que lo implementa, sirve para acceder a máquinas remotas a través de una red. Permite manejar por completo la computadora mediante un intérprete de comandos.

Además de la conexión a otros dispositivos, SSH nos permite copiar datos de forma segura (tanto ficheros sueltos como simular sesiones FTP cifradas), gestionar claves para no escribir claves al conectar a los dispositivos y pasar los datos de cualquier otra aplicación por un canal seguro tunelizado mediante SSH.

SSH trabaja de forma similar a como se hace con telnet. La diferencia principal es que SSH usa técnicas de cifrado que hacen que la información que viaja por el medio de comunicación vaya de manera no legible y ninguna tercera persona pueda descubrir el usuario y contraseña de la conexión ni lo que se escribe durante toda la sesión; aunque es posible atacar este tipo de sistemas por medio de ataques de REPLAY y manipular así la información entre destinos. [8].

Ejemplo:

Para conectarnos al equipo 192.168.10.112, lo podemos hacer de la siguiente manera.

Ssh 192.168.10.112 nos permite conectar al equipo con tal dirección IP

Ssh [email protected] nos permite conectar al equipo con esa IP, con la sesión de user12

Ssh tablet12 nos permite conectar al equipo con la dirección IP asociada a tablet12, datos que están alojados en el archivo /etc/hosts

Ssh [email protected] nos permite conectar al equipo con la dirección IP asociada a tablet12, con la sesión de user12.

Para desconectarnos de la sesión remota, utilizamos el comando logout.

En estos ejemplos, no nos pidió contraseña alguna, porque anteriormente creamos una llave pública que permite la libre conexión.

Page 10: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

10

7.1. Creación de llave publica Para poder ejecutar nuestros programas en varios procesadores que están en distintas maquinas, se necesita de una llave pública. Si los equipos tienen una llave privada, se pierde dinamismo, ya que cada vez que accedemos a la ejecución de una tarea sobre el CPU de otra computadora, nos pedirá la clave del otro equipo. Una forma de crear una llave pública es: Desde del directorio $HOME del usuario: pepe@cliente:~$ ssh-keygen -b 4096 -t rsa Eso genera $HOME/.ssh/id_rsa y $HOME/.ssh/id_rsa.pub que son las claves privadas y publica para el sistema RSA. Copiar la clave pública a otros hosts Utilizando el programa SSH: pepe@cliente$ ssh-copy-id pepe@servidor O copiando a mano la clave pública de tu usuario@host en el fichero authorized_keys de la máquina que quieres que te deje entrar sin clave. pepe@cliente:~$ scp .ssh/id_rsa.pub pepe@servidor:.ssh/nueva_clave pepe@cliente:~$ ssh pepe@servidor pepe@servidor:~$ cd .ssh/ pepe@servidor:~$ cat nueva_clave >> authorized_keys pepe@servidor:~$ rm nueva_clave Otra forma de hacerlo en un solo comando es: pepe@cliente$ cat ~/.ssh/id_rsa.pub | ssh pepe@servidor „cat – >> ~/.ssh/authorized_keys‟ En todos los casos, el directorio .ssh en el servidor debe existir y el fichero authorized_keys debe tener los permisos correctos (0600). La primera vez que se accede a una máquina se almacena su host_key en el fichero $HOME/.ssh/know_hosts. A partir se ese momento podemos utilizar ssh y scp con esa máquina sin necesidad de escribir la clave.

8. SFTP (Secure File Transfer Protocol)

Es un protocolo de red que proporciona la funcionalidad necesaria para la transferencia y manipulación de archivos sobre un flujo de datos fiable. Se utiliza comúnmente con SSH para proporcionar la seguridad a los datos, aunque permite ser usado con otros protocolos de seguridad. Por lo tanto, la seguridad no la provee directamente el protocolo SFTP, sino SSH o el protocolo que sea utilizado en su caso para este cometido.

Page 11: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

11

Para transmisión de archivos, por este medio, los pasos son exactamente los mismos que se realizaron con ssh, la diferencia, es que ahora se utiliza sftp en su lugar.

En la imagen, podemos observar como conectarnos a la tablet 12 utilizando el comando sftp tablet12. Usamos el comando put para cargar un programa de nuestro equipo a la tablet 12 en el directorio actual, con el comando get, copiamos un archivo especifico de la tablet 12 a nuestro equipo, en esta ocasión, usamos el comando bye para dar por finalizada la sesión remota.

9. Protocolos de comunicación

La comunicación entre los equipos que están inmersos en una red, se lleva a distintos niveles, como se menciono anteriormente, el SSH y el SFTP pertenecen a la capa del nivel 3 del modelo OSI, que corresponden a la comunicación a nivel red, si nosotros queremos transmitir paquetes entre un equipo y otro, esto exige una comunicación a nivel 4, es decir, capa de transporte, a nivel capa de transporte, podemos encontrar los protocolos UDP.

9.1. Protocolos UDP (User Datagram Protocol)

Es un protocolo del nivel de transporte basado en el intercambio de datagramas. Permite el envío de datagramas a través de la red sin que se haya establecido previamente una conexión, ya que el propio datagrama incorpora suficiente información de direccionamiento en su cabecera. Tampoco tiene confirmación ni control de flujo, por lo que los paquetes pueden adelantarse unos a otros; y tampoco se sabe si ha llegado correctamente, ya que no hay confirmación de entrega o recepción.

9.2. Socket UDP

Los sockets UDP no son orientados a conexión. Un programa puede abrir un socket y ponerse a escribir mensajes en él o leer, sin necesidad de esperar a que alguien se conecte en el otro extremo del socket. El protocolo UDP, al no ser orientado a conexión, no garantiza que el mensaje llegue a su destino. Parece claro que si mi programa envía un mensaje y no hay nadie escuchando, ese mensaje se pierde. De todas formas, aunque haya alguien escuchando, el protocolo tampoco garantiza que el mensaje llegue. Lo único que garantiza es, que si llega, llega sin errores.

Page 12: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

12

Este tipo de sockets se suele usar para información no vital, por ejemplo, envío de gráficos a una pantalla. Si se pierde algún gráfico por el camino, veremos que la pantalla pierde un refresco, pero no es importante. El que envía los gráficos puede estar dedicado a cosas más importantes y enviar los gráficos sin preocuparse (y sin quedarse bloqueado) si el otro los recibe o no.

El concepto de cliente/servidor sigue teniendo aquí el mismo sentido. El servidor abre un socket UDP en un servicio conocido por los clientes y se queda a la escucha del mismo. El cliente abre un socket UDP en cualquier servicio/puerto que esté libre y envía un mensaje al servidor solicitando algo. La diferencia principal con los TCP (orientados a conexión), es que en estos últimos ambos sockets (de cliente y de servidor) están conectados y lo que escribimos en un lado, sale por el otro. En un UDP los sockets no están conectados, así que a la hora de enviar un mensaje, hay que indicar quién es el destinatario.

En los sockets orientados a conexión se envían mensajes con write() o send() y se reciben con read() o recv(). En un socket no orientado a conexión hay que indicar el destinatario, así que se usan las funciones sendto() y recvfrom().Uno de los sockets que se probó en este proyecto, es el siguiente:

9.2.1. Servidor

/*** server.c -- a stream socket server demo*/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <signal.h> #define MYPORT 3490 // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold void sigchld_handler(int s){ while(waitpid(-1, NULL, WNOHANG) > 0); } int main(void){ int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct sockaddr_in my_addr; // my address information struct sockaddr_in their_addr; // connector's address information socklen_t sin_size; struct sigaction sa; int yes=1; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) ==-1) { perror("setsockopt"); exit(1); } my_addr.sin_family = AF_INET; // host byte order

Page 13: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

13

my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1) { perror("bind"); exit(1); } if (listen(sockfd, BACKLOG) == -1) { perror("listen"); exit(1); } sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } while(1) { // main accept() loop sin_size = sizeof(struct sockaddr_in); if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,&sin_size)) == -1) { perror("accept"); continue; } printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr)); if (!fork()) { // this is the child process close(sockfd); // child doesn't need the listener if (send(new_fd, "Hello, world!\n", 14, 0) == -1) perror("send"); close(new_fd); exit(0); } close(new_fd); // parent doesn't need this } return 0; }

9.2.2. Cliente

/*** client.c -- a stream socket client demo*/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define PORT 3490 // the port client will be connecting to #define MAXDATASIZE 100 // max number of bytes we can get at once

Page 14: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

14

int main(int argc, char *argv[]){ int sockfd, numbytes; char buf[MAXDATASIZE]; struct hostent *he; struct sockaddr_in their_addr; // connector's address information if (argc != 2) { fprintf(stderr,"usage: client hostname\n"); exit(1); } if ((he=gethostbyname(argv[1])) == NULL) { // get the host info perror("gethostbyname"); exit(1); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(PORT); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr); memset(&(their_addr.sin_zero), '\0', 8); // zero the rest of the struct if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) { perror("connect"); exit(1); } if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { perror("recv"); exit(1); } buf[numbytes] = '\0'; printf("Received: %s",buf); close(sockfd); return 0; }

Para ejecutar los códigos, se siguen las siguientes instrucciones:

El servidor se compila así: gcc -o server sever.c y se ejecuta con ./server

El cliente se compila con: gcc -o cliente cliente.c y se ejecuta con ./client localhost o ./cliente <IP_servidor>

Page 15: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

15

Primero se debe ejecutar el servidor y después el cliente. En caso contrario, la comunicación no se llevara

acabo. Se anexa otro socket que se implemento:

9.2.3. Servidor

#include "udp.h" #define DATA 1 #define ACK 2 #define MAX 16 char IP[MAX]; char hostlocal[MAX]; typedef struct ctrl { unsigned char type; unsigned short len; }CTRL; typedef struct mssg { CTRL cntrl; unsigned char data [1500]; } MSSG; void recibe(){ UDP canal; MSSG m; int i; struct timeval timer; fd_set lista_fd; int ready; create_UDP (&canal,hostlocal, 8001, IP , 8000); canal.buffer = (char *)&m; canal.capacity = sizeof (MSSG); FD_SET (canal.sockfd, &lista_fd); timer.tv_sec = 10; timer.tv_usec = 400000; ready = select (canal.sockfd+1, &lista_fd, NULL, NULL, &timer); if (ready > 0 && FD_ISSET (canal.sockfd, &lista_fd)) { recv_UDP (&canal); printf ("tipo: %d, len:%d, data: %s\n", m.cntrl.type, m.cntrl.len, m.data); } else { printf ("Expiro el temporizador\n"); exit (1); }

Page 16: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

16

} void envia(){ UDP canal; MSSG m; int i; create_UDP (&canal, hostlocal, 8000, IP , 8001); canal.buffer = (char *)&m; strcpy (m.data, "Este es un mensaje desde el servidor 192.168.10.112"); canal.bytes_to_send = sizeof (CTRL) + strlen (m.data) + 1; m.cntrl.type = DATA; m.cntrl.len = canal.bytes_to_send; send_UDP (&canal); } void limpia(){ int i; for(i=0;i<MAX;i++) IP[i]='\0'; } main(int argc, char *argv[]){ int i=0; limpia(); strcpy(IP,argv[1]); strcpy(hostlocal,"192.168.10.112"); envia(); recibe(); }

9.2.4. Cliente

#include <sys/select.h> #include "udp.h" #define DATA 1 #define ACK 2 #define MAX 16 char IP[MAX]; char hostlocal[MAX]; typedef struct ctrl { unsigned char type; unsigned short len; }CTRL; typedef struct mssg { CTRL cntrl; unsigned char data [1500]; } MSSG; void envia(){ UDP canal; MSSG m;

Page 17: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

17

int i; create_UDP (&canal,hostlocal , 8000, IP , 8001); canal.buffer = (char *)&m; strcpy (m.data, "Este es un mensaje desde el cliente 192.168.10.111"); canal.bytes_to_send = sizeof (CTRL) + strlen (m.data) + 1; m.cntrl.type = ACK; m.cntrl.len = canal.bytes_to_send; send_UDP (&canal); } void recibe(){ UDP canal; MSSG m; int i; struct timeval timer; fd_set lista_fd; int ready; create_UDP (&canal, hostlocal , 8001, IP , 8000); canal.buffer = (char *)&m; canal.capacity = sizeof (MSSG); FD_SET (canal.sockfd, &lista_fd); timer.tv_sec = 15; timer.tv_usec = 400000; ready = select (canal.sockfd+1, &lista_fd, NULL, NULL, &timer); if (ready > 0 && FD_ISSET (canal.sockfd, &lista_fd)) { recv_UDP (&canal); printf (" tipo: %d, len:%d, data: %s\n", m.cntrl.type, m.cntrl.len, m.data); } else { printf ("Expiro el temporizador\n"); exit (1); } } void limpia(){ int i; for(i=0;i<MAX;i++) IP[i]='\0'; } main (int argc,char *argv[]){ int i=0; limpia(); strcpy(IP,argv[1]); strcpy(hostlocal,"192.168.10.111"); recibe(); sleep(4); envia(); } Para ejecutar los códigos, se siguen las siguientes instrucciones: El servidor se compila así: gcc -o funcionando funcionando.c y se ejecuta con ./funcionando <ip_equipo_cliente>

Page 18: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

18

El cliente se compila con: gcc -o cliente funcionando.c y se ejecuta con ./funcionando <ip_servidor> En la dinámica de ejecución, el cliente se lanza primero, esta a la espera de recibir algo, cuando recibe el paquete, realiza una espera, para que el servidor lo “alcance” y le contesta. Problemas de esta implementación: La sincronización, si el servidor se lanza primero, el cliente perderá los datos, y se perderá la conexión, la solución radica en el control de errores, esa mejora hay que realizar. Estos 2 últimos programas utilizan una librería especial, se anexa el código de la librería UDP.h: /// Librería para establecer asociaciones UDP de manera sencilla, ocultando /// los detalles de programación específicos al manejo de socket UNIX. /// Autor: Luis Rojas Cardenas, 2005 #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <time.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #define CLIENTE 0 #define SERVIDOR 1 /******************************************************************/ /* create_UPD: crea un socket UDP. serv: contiene informacion relacionada con el servidor. addr; dirección del servidor; valida solo cuando type = 1 port: numero de puerto a asociar con el socket creado. type: 0 = cliente, 1 = servidor. regresa: el descriptor del socket. */ typedef struct udp { int sockfd; struct sockaddr_in foreign; struct sockaddr_in local; int capacity; int received_bytes; int bytes_to_send; int sent_bytes; char *buffer; } UDP; /* void print_UDP (UDP *udp) { printf ("foreing address : %s\n", inet_ntoa (udp->foreign.sin_addr)); printf ("foreing port : %d\n", ntohs (udp->foreign.sin_port)); printf ("local address : %s\n", inet_ntoa (udp->local.sin_addr)); printf ("local port : %d\n", ntohs (udp->local.sin_port)); printf ("buffer capacity : %d\n", udp->capacity); } */

Page 19: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

19

void create_UDP (UDP *udp, char *laddr, unsigned short lport, char *faddr, unsigned short fport){ bzero ((void *)udp, sizeof (UDP)); if ((udp->sockfd = socket (PF_INET, SOCK_DGRAM, 0)) < 0) { puts ("Problemas al abrir el socket"); exit (1); } // printf ("socket() OK\n"); bzero ((void *)&(udp->foreign), sizeof (struct sockaddr_in)); bzero ((void *)&(udp->local), sizeof (struct sockaddr_in)); // printf ("bzero () OK\n"); udp->foreign.sin_family = udp->local.sin_family = AF_INET; udp->foreign.sin_addr.s_addr = inet_addr (faddr); udp->foreign.sin_port = htons (fport); if (laddr == NULL) { printf ("local address 'laddr' is NULL, I can not continue \n"); exit (1); } udp->local.sin_addr.s_addr = inet_addr (laddr); udp->local.sin_port = htons (lport); if (bind (udp->sockfd, (struct sockaddr *)&(udp->local), sizeof (struct sockaddr_in)) < 0) { printf ("problems with 'bind'\n"); exit (1); }; // printf ("bind () OK\n"); } /******************************************************************/ void send_UDP (UDP *udp){ udp->sent_bytes = sendto (udp->sockfd, (void *)udp->buffer, udp->bytes_to_send, 0, (struct sockaddr *)&(udp->foreign), (socklen_t) sizeof (struct sockaddr_in)); if (udp->sent_bytes < 0) { puts ("Error with 'sendto'"); exit (1); } } /******************************************************************/ /* recv_UPD: Recibe datos en una asociacion UDP */ void recv_UDP (UDP *udp){ int fromlen; fromlen = sizeof (struct sockaddr_in); udp->received_bytes = recvfrom (udp->sockfd, (void *)udp->buffer, udp->capacity, 0, (struct sockaddr *) &(udp->foreign),(socklen_t *)&fromlen); } void close_UDP (UDP *udp){ close (udp->sockfd); }

Page 20: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

20

9.3. MPI (Interfaz de Paso de Mensajes) Es un estándar que define la sintaxis y la semántica de las funciones contenidas en una biblioteca de paso de mensajes diseñada para ser usada en programas que exploten la existencia de múltiples procesadores. El paso de mensajes es una técnica empleada en programación concurrente para aportar sincronización entre procesos y permitir la exclusión mutua, de manera similar a como se hace con los semáforos, monitores, etc. Su principal característica es que no precisa de memoria compartida, por lo que es muy importante en la programación de sistemas distribuidos. Los elementos principales que intervienen en el paso de mensajes son el proceso que envía, el que recibe y el mensaje. Dependiendo de si el proceso que envía el mensaje espera a que el mensaje sea recibido, se puede hablar de paso de mensajes síncrono o asíncrono. En el paso de mensajes asíncrono, el proceso que envía, no espera a que el mensaje sea recibido, y continúa su ejecución, siendo posible que vuelva a generar un nuevo mensaje y a enviarlo antes de que se haya recibido el anterior. Por este motivo se suelen emplear buzones, en los que se almacenan los mensajes a espera de que un proceso los reciba. Generalmente empleando este sistema, el proceso que envía mensajes sólo se bloquea o para, cuando finaliza su ejecución, o si el buzón está lleno. En el paso de mensajes síncrono, el proceso que envía el mensaje espera a que un proceso lo reciba para continuar su ejecución. Por esto se suele llamar a esta técnica encuentro, o rendezvous. Dentro del paso de mensajes síncrono se engloba a la llamada a procedimiento remoto, muy popular en las arquitecturas cliente/servidor. La Interfaz de Paso de Mensajes (conocido ampliamente como MPI, siglas en inglés de Message Passing Interface) es un protocolo de comunicación entre computadoras. Es el estándar para la comunicación entre los nodos que ejecutan un programa en un sistema de memoria distribuida. Las implementaciones en MPI consisten en un conjunto de bibliotecas de rutinas que pueden ser utilizadas en programas escritos en los lenguajes de programación C, C++, Fortran y Ada. La ventaja de MPI sobre otras bibliotecas de paso de mensajes, es que los programas que utilizan la biblioteca son portables (dado que MPI ha sido implementado para casi toda arquitectura de memoria distribuida), y rápidos, (porque cada implementación de la biblioteca ha sido optimizada para el hardware en la cual se ejecuta). Algunas características:

Estandarización. Portabilidad: multiprocesadores, multicomputadores, redes, heterogéneos Buenas prestaciones. Amplia funcionalidad. Existencia de implementaciones libres (mpich, LAM-MPI, ...)

La especificación detalla las funciones que se pueden utilizar, no el modo como se compilan y lanzan-ejecutan los programas, lo cual puede variar de una implementación a otra. Siguiendo el modelo SPMD, el usuario escribirá su aplicación como un proceso secuencial del que se lanzarán varias instancias que cooperan entre sí. Los procesos invocan diferentes funciones MPI que permiten

Iniciar, gestionar y finalizar procesos MPI Comunicar datos entre dos procesos Realizar operaciones de comunicación entre grupos de procesos Crear tipos arbitrarios de datos

Page 21: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

21

En el archivo /etc/hosts están almacenados nuestros equipos que pertenecen a nuestra red, si nosotros deseamos anexar uno o almacenar otro, ese archivo es el que debemos de modificar, la sintaxis para agregar algún equipo, es de la siguiente manera: #<IP> nombre Por ejemplo, si nosotros deseamos guardar nuestros equipos 192.168.10.11 y 192.168.10.12, la sintaxis sería: 192.168.10.111 tablet11 192.168.10.112 tablet12 Para correr nuestros programas en modo dinámico, con programación MPI, nosotros debemos ejecutar un comando que se llama lamboot, la sintaxis es: lamboot -v maquinas. Es decir, nosotros debemos de tener creado un archivo llamado maquinas, donde se almacenara el numero de procesadores a los que se podrá tener acceso sobre un equipo especifico y el nombre de la maquina. El archivo maquinas, es de la siguiente manera: <dir_ip> CPU=<numero de veces> Ejemplo: 192.168.10.111 cpu=2 O dado que ya tenemos almacenado esta dirección en el archivo /etc/hosts, podemos hacer referencia al equipo con su nombre: tablet11 cpu=2 En este momento, ya podemos ejecutar un programa en MPI sobre nuestras máquinas. Para ello, necesitamos compilar nuestro programa con la siguiente instrucción: mpicc -o archivo_destino archivo_origen.c Para ejecutarlo, seguimos la siguiente instrucción: mpirun -np <numero de veces a ejecutar> archivo_destino A continuación, se anexa uno de los códigos que se probaron: [user12@tablet11 ~]$ more mpihello.c #include <stdio.h> #include "mpi.h" int main(int argc, char *argv[]){ int rank; int size; char nom[12];

Page 22: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

22

MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&size); MPI_Comm_rank(MPI_COMM_WORLD,&rank); gethostname(nom,12); printf("Hola desde %d, de un total de: %d maquina %s\n", rank, size,nom); MPI_Finalize(); return 0; }

En este caso, no hubo mayor problema para acceder a las otras maquinas, ya que tenemos creada una llave publica que nos permite dicha ejecución. Es importante, que las maquinas que estén involucradas en la ejecución deben de tener necesariamente el archivo ejecutable sobre la misma carpeta en la que lo tiene el servidor. Las cuestiones claves de este tipo de programación, es que a pesar de que no hay perdida de datos, hay que tener cuidado en la sincronización y sobre como queremos que se lleve a cabo la ejecución. Al ejecutar los proceso, se puede llevar a cabo las tareas de distintas formas, una de ellas es, que el servidor envíe la señal a un equipo, este realice la ejecución, cundo termine, le devuelva la señal al servidor, y este le de el mando al siguiente equipo y así sucesivamente, hasta que se ha recorrido toda la red. Otra forma, es que el servidor le mande la señal a un equipo, el cliente lo ejecute y en lugar de darle la señal al servidor, se lo envíe a otro equipo y así sucesivamente, hasta que termine el programa. A continuación, presento un código, que realiza el paso de mensajes de manera síncrona, es decir, el proceso i manda el mensaje al proceso i+1:

#include <stdio.h>

#include <mpi.h>

int main(int argc, char *argv[]){

MPI_Status status;

int num, rank, size, tag, next, from;

srand(time(NULL));

Page 23: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

23

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &rank);

MPI_Comm_size(MPI_COMM_WORLD, &size);

tag = 0;

next = (rank + 1) % size;

from = (rank + size - 1) % size;

if(rank==0){

num=rand(time(NULL))%100;

printf("Proceso %d envia %d al %d\n", rank, num, next);

MPI_Send(&num, 1, MPI_INT,next, tag, MPI_COMM_WORLD);

}

do {

MPI_Recv(&num, 1, MPI_INT, from, tag, MPI_COMM_WORLD, &status);

if(num>0) num--;

if(num==0){printf("Proceso %d, GANE\n",rank);num=rank*(-1)-1;};

if(num>0){printf("Proceso %d envia %d al %d\n", rank, num, next);}

if(num<0 && rank!=(num*(-1)-1)){printf("Proceso %d, PERDI, gano el proceso: %d\n",rank,num*(-1)-1);}

MPI_Send(&num, 1, MPI_INT, next, tag, MPI_COMM_WORLD);

} while (num > 0);

MPI_Finalize();

return 0;

}

9.4. Socket UDP vs MPI (Interfaz de Paso de Mensajes)

La decisión sobre como comunicaremos nuestros equipos, me hizo inclinarme por los Socket UDP, ya que a pesar de que la programación MPI, evita problemas de sincronización, de retraso y de pèrdida de datos entre algunas cuestiones, centraliza la ejecución al servidor, y no permite observar la ejecución de un proceso en los

Page 24: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

24

demás equipos, cuestión que si nos lo permite los socket UDP, además de que estos últimos, permite una cierta independencia de cada equipo.

10. Interfaz gráfica

Se probaron varios entornos gráficos, entre los cuales están, ncurses, cairo y gtk. A continuación, presento lo obtenido.

10.1. GTK+

GTK+ (The GIMP Toolkit), es un conjunto de bibliotecas multiplataforma para desarrollar interfaces gráficas de usuario (GUI), principalmente para los entornos gráficos GNOME, XFCE y ROX aunque también se puede usar en el escritorio de Windows, MacOS y otros. Esta biblioteca contiene los objetos y funciones necesarias para crear una interfaz de usuario. Maneja widgets como ventanas, botones, menús, etiquetas, deslizadores, pestañas, etc.

GTK+ se ha diseñado para permitir programar con lenguajes como C, C++, C#, Java, Ruby, Perl, PHP o Python.

Ejemplos de un programa en GTK:

El siguiente còdigo, nos permite crear una ventana simple.

#include <gtk/gtk.h> int main (int argc, char *argv[]) { GtkWidget *window; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_show (window); gtk_main (); return 0; }

Otro codigo:

/* Basado en ejemplos de http://www.gtk.org/tutorial/

* Se compila con: gcc -o dibujo `pkg-config --cflags --libs gtk+-2.0` dibujo.c */

#include <glib.h>

#include <gdk/gdk.h>

#include <gtk/gtk.h>

/* Función 'callback' para atender el evento "expose_event" */

Page 25: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

25

static gboolean on_dibujo_expose_event(GtkWidget* widget, GdkEvent* event, gpointer data){

/* obtiene contexto gráfico del dibujo */

GdkGC* gc = gdk_gc_new(GDK_DRAWABLE(widget->window));

/* color */

GdkColor color;

g_print("[recibido el evento expose_event]\n");

/* cambio propiedades del contexto gráfico gc*/

gdk_gc_set_line_attributes(gc,

2, /* grosor */

GDK_LINE_SOLID, /* tipo de línea (sólida en este caso) */

GDK_CAP_ROUND, /* terminación (redondeada en este caso) */

GDK_JOIN_ROUND); /* unión de trazos (redondeado en este caso) */

/* pongo color en rojo (cada color tiene 16 bits) */

color.red = 0xFFFF;

color.green = 0;

color.blue = 0;

/* reservo el color (o pido uno cercano) */

gdk_colormap_alloc_color(gtk_widget_get_colormap(widget), &color,

FALSE, /* sólo lectura, para poder compartirlo */

TRUE); /* si no lo puede reservar, pide uno parecido */

/* uso el color como color del trazo para dibujar */

gdk_gc_set_foreground(gc, &color);

/* dibujo una línea */

gdk_draw_line(

GDK_DRAWABLE(widget->window), /* área en donde dibujar */

gc, /* contexto gráfico a utilizar */

10, 10, /* (x, y) inicial */

190, 190); /* (x, y) final */

/* libero memoria */

g_object_unref(G_OBJECT(gc));

return FALSE;

}

/* Función 'callback' para atender la señal del evento "delete_event" */

static gboolean on_delete_event(GtkWidget* widget, GdkEvent* event, gpointer data){

g_print ("[recibido el evento delete_event]\n");

return FALSE;

Page 26: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

26

}

/* Función 'callback' para atender la señal "destroy" de la ventana. */

static void on_destroy(GtkWidget *widget, gpointer data){

g_print ("[recibido el evento destroy]\n");

/* finaliza el loop de gtk_main() y libera memoria */

gtk_main_quit();

}

int main(int argc, char* argv[]){

GtkWidget* ventana;

GtkWidget* dibujo;

/* inicia gtk, usando parámetros de la línea de comandos */

gtk_init(&argc, &argv);

/********************************* VENTANA *******************************/

/* creo a una nueva ventana */

ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);

/* conecto la señal "delete_event" de la ventana a la callback on_delete_event() */

g_signal_connect(G_OBJECT(ventana), "delete_event",

G_CALLBACK(on_delete_event), NULL);

/* conecto la señal "destroy" de la ventana a la callback destruir() */

g_signal_connect(G_OBJECT(ventana), "destroy", G_CALLBACK(on_destroy), NULL);

/********************************** DIBUJO *******************************/

/* creo un área de dibujo */

dibujo = gtk_drawing_area_new();

/* conecto la señal "expose_event" del dibujo a la callback

* on_dibujo_expose_event() para que se redibuje cuando sea necesario */

g_signal_connect(G_OBJECT(dibujo), "expose_event",

G_CALLBACK(on_dibujo_expose_event), NULL);

/* agrega el dibujo a la ventana */

gtk_container_add(GTK_CONTAINER(ventana), dibujo);

/********************************* PROGRAMA ******************************/

/* muestra la ventana */

Page 27: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

27

gtk_widget_show_all(ventana);

/* comienza el loop de eventos */

gtk_main();

return 0;

}

El codigo anterior, fue uno de tantos códigos que probe y me di a la tarea de entender e investigar, con la finalidad de presentar un cìrculo en pantalla, capaz de trasladarlo a distintas funciones, en función de tiempos, este còdigo que presente, lo que realiza, es presentar una línea en pantalla, trabaja en función de señales, entendiendo como señal, cualquier pulso, teclado, o clic recibido en pantalla a través de cualquier medio, cuando sucede ello, renderiza la pantalla, y vuelve a mostrar la imagen, hasta que se hace referencia a la función destroy. El còdigo siguiente, fue uno de mis intentos por mostrar una imagen en pantalla, y cumplir mi cometido.

/* vim: set et sw=4 sts=4 : * Basado en ejemplos de http://www.gtk.org/tutorial/ * Se compila con: * gcc -o dibujo `pkg-config --cflags --libs gtk+-2.0` dibujo.c */ #include <glib.h> #include <gdk/gdk.h> #include <gtk/gtk.h> int y=20,auxiliar=200; /* Función 'callback' para atender la señal del evento "delete_event" */ static gboolean on_delete_event(GtkWidget* widget, GdkEvent* event,gpointer data){ g_print ("[recibido el evento delete_event]\n"); return FALSE; } //dibujo static gboolean on_dibujo_expose_event1(GtkWidget* widget, GdkEvent* event,gpointer data){ /* obtiene contexto gráfico del dibujo */ GdkGC* gc = gdk_gc_new(GDK_DRAWABLE(widget->window)); /* color */ GdkColor color; // La siguiente línea nos sirve para definir las coordenadas // del centro de nuestro polygono // GdkPoint *points; int width, height; // points->x=10; // points->y=10; gdk_window_get_size(widget->window, &width, &height); //color=(GdkColor *)malloc(sizeof(GdkColor)); //width=5; //height=5; color.red=1; color.green=0; color.blue=0; color.pixel=(gulong)(115 +0 +0);

Page 28: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

28

/* reservo el color (o pido uno cercano) */ gdk_colormap_alloc_color(gtk_widget_get_colormap(widget), &color, FALSE, /* sólo lectura, para poder compartirlo */ TRUE); /* si no lo puede reservar, pide uno parecido */ gdk_gc_set_foreground(gc,&color); gdk_draw_rectangle(widget->window,gc,1,y,y,15,15); // Con la siguiente línea, dibujamos un poligono de 6 lados //gdk_draw_polygon(widget->window,gc,1, points,6 ); y=y+15; g_print("[recibido el evento expose_event]\n"); /* libero memoria */ g_object_unref(G_OBJECT(gc)); return FALSE; } /* Función 'callback' para atender la señal "destroy" de la ventana. */ static void on_destroy(GtkWidget *widget, gpointer data){ g_print ("[recibido el evento destroy]\n"); /* finaliza el loop de gtk_main() y libera memoria */ gtk_main_quit(); } int main(int argc, char* argv[]){ GtkWidget* ventana; GtkWidget* dibujo; gtk_init(&argc, &argv); gint i=0; ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(ventana,1250,700); dibujo = gtk_drawing_area_new(); for(i=0;i<40;i++){ g_signal_connect(G_OBJECT(dibujo), "expose_event", G_CALLBACK(on_dibujo_expose_event1), NULL); g_signal_connect(G_OBJECT(ventana), "delete_event", G_CALLBACK(on_delete_event), NULL); } gtk_container_add(GTK_CONTAINER(ventana), dibujo); gtk_widget_show_all(ventana); gtk_main(); return 0; }

Page 29: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

29

En la figura, se muestra un cuadrado desplazado varias veces. Se pretendia, que conforme avanzaba el cuadro, la pantalla se redefiniera y mostrara solo el cuadrado en cuestión. El problema, es que los cambios que marcan el renderizado de la pantalla, funciona a base de señales, y solo actúa en función de ello. No encontré la manera de controlar los cambios en función de los tiempos, la función gtk_main() realiza el loop de eventos, y lo realiza de una forma muy peculiar, ya que quise implementar el codigo con una espera dentro del ciclo que controla el desplazamiento del cuadrado, pero sucedía que, primero realizaba la espera total, y después, comenzaba a marcar los cuadrados en escena, es decir, todos al mismo tiempo.

En el còdigo, aparecen unas líneas con color violeta, con esas líneas, nosotros podemos mostrar un polígono

en pantalla.

10.2. Ncurses

Es una biblioteca de programación que provee una API que permite al programador escribir interfaces basadas en texto, TUIs. También optimiza el refresco de la pantalla, lo que permite reducir la latencia experimentada cuando se usan intérpretes de comandos remotos. Ncurses significa «new curses», ya que es un reemplazo del descontinuado curses.

El proyecto provee APIs oficiales en C, C++ y Ada, aunque también hay bindings para otros lenguajes, como Perl, Python o Vala. Forma parte del proyecto GNU. Es uno de los pocos programas de GNU que no se distribuye bajo la GPL ni bajo la LGPL, sino bajo la licencia MIT.

Después de varios códigos revisados y modificaciones realizadas, el codigo que utilizamos como guía para nuestra interfaz gráfica, es el siguiente. Implemente la interfaz grafica sobre ncurses, porque fue la que me permitió más prestaciones y ejecutar con éxito mi meta, además, de que el codigo es compatible con el que utilice en mis sockets.

//gcc -o nombre nombre.c -l m -l ncurses #include <ncurses.h> #include <time.h> WINDOW *create_newwin(int height, int width, int starty, int startx); void destroy_win(WINDOW *local_win); int main(int argc, char *argv[]){ WINDOW *my_win;

Page 30: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

30

int startx, starty, width, height; int ch,i,y,bandera=1,numero; srand (time(NULL)); initscr(); for(y=0;y<100;y++){ height = 2; width = 3;

starty = 0; startx = 0; refresh(); my_win = create_newwin(height, width, starty, startx);

if(bandera==1){ while(startx<79){ if(numero==0) numero = -1; if(starty==0) numero = 1; if(starty==19) numero = -1;

starty=starty+numero; destroy_win(my_win); my_win = create_newwin(height, width, starty,startx++); usleep(50000); } } sleep(2); endwin(); } return 0; } WINDOW *create_newwin(int height, int width, int starty, int startx){ WINDOW *local_win; local_win = newwin(height, width, starty, startx); box(local_win,0,0); // 0, 0 gives default characters // for the vertical and horizontal // lines wrefresh(local_win); // Show that box return local_win; } void destroy_win(WINDOW *local_win){ /* box(local_win, ' ', ' '); : This won't produce the desired result of erasing the window. It will leave it's four cor- ner and so an ugly remnant of window. */ wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); /* The parameters taken are * 1. win: the window on which to operate * 2. ls: character to be used for the left side of the window * 3. rs: character to be used for the right side of the window * 4. ts: character to be used for the top side of the window * 5. bs: character to be used for the bottom side of the window * 6. tl: character to be used for the top left corner of the window * 7. tr: character to be used for the top right corner of the window * 8. bl: character to be used for the bottom left corner of the window

Page 31: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

31

* 9. br: character to be used for the bottom right corner of the window */ wrefresh(local_win); delwin(local_win); }

10.3. Cairo

Es una biblioteca de renderizado avanzado de controles de aplicación. Una biblioteca gráfica de la API GTK+ usada para proporcionar imágenes basadas en gráficos vectoriales. Aunque cairo es una API independiente de dispositivos, está diseñado para usar aceleración por hardware cuando esté disponible. Cairo deja disponibles numerosas primitivas de imágenes de segunda dimensión.

A pesar de que está escrito en C, existen implementaciones en otros lenguajes de programación, incluyendo C++, C#, Common Lisp, Haskell, Java, Python, Perl, Ruby, Scheme (Guile, Chicken), Smalltalk y muchos otros. Dada la doble licencia incluyendo la Licencia Pública General Reducida de GNU y la Licencia Pública de Mozilla, cairo es software libre.

Uno de los programas que probe utilizando esta librerìa, es la siguiente: //hello.c #include <cairo.h> Int main (int argc, char *argv[]){ cairo_surface_t *surface; cairo_t *cr; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 240, 80); cr = cairo_create (surface); cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, 32.0); cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); cairo_move_to (cr, 10.0, 50.0); cairo_show_text (cr, "Hello, world"); cairo_destroy (cr); cairo_surface_write_to_png (surface, "hello.png"); cairo_surface_destroy (surface); return 0; }

La instrucción para compilarlo es:

cc -o hello $(pkg-config --cflags --libs cairo) hello.c

Después de correr el archivo ejecutable hello, el usuario obtendrá una imagen PNG llamada hello.png con el texto "Hello, world" escrito en color azul.

Page 32: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

32

11. Con visión al resultado

Al final, obtuve 2 soluciones con sockets:

La primera, es la siguiente:

Funcionando.c

#include "udp.h"

#define DATA 1

#define ACK 2

#define MAX 16

char IP[MAX];

char hostlocal[MAX];

typedef struct ctrl {

unsigned char type;

unsigned short len;

}CTRL;

typedef struct mssg {

CTRL cntrl;

unsigned char data [1500];

} MSSG;

void recibe(){

UDP canal;

MSSG m;

int i;

struct timeval timer;

fd_set lista_fd;

Page 33: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

33

int ready;

create_UDP (&canal,hostlocal, 8001, IP , 8000);

canal.buffer = (char *)&m;

canal.capacity = sizeof (MSSG);

FD_SET (canal.sockfd, &lista_fd);

timer.tv_sec = 10;

timer.tv_usec = 400000;

ready = select (canal.sockfd+1, &lista_fd, NULL, NULL, &timer);

if (ready > 0 && FD_ISSET (canal.sockfd, &lista_fd)) {

recv_UDP (&canal);

printf ("tipo: %d, len:%d, data: %s\n", m.cntrl.type, m.cntrl.len, m.data);

} else {

printf ("Expiro el temporizador\n");

exit (1);

}

}

void envia(){

UDP canal;

MSSG m;

int i;

create_UDP (&canal, hostlocal, 8000, IP , 8001);

canal.buffer = (char *)&m;

strcpy (m.data, "Este es un mensaje desde el servidor 192.168.10.112");

canal.bytes_to_send = sizeof (CTRL) + strlen (m.data) + 1;

m.cntrl.type = DATA;

m.cntrl.len = canal.bytes_to_send;

send_UDP (&canal);

}

void limpia(){

int i;

for(i=0;i<MAX;i++) IP[i]='\0';

}

main(int argc, char *argv[]){

int i=0;

Page 34: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

34

limpia();

strcpy(IP,argv[1]);

strcpy(hostlocal,"192.168.10.112");

envia();

recibe();

}

Funcionando1.c

#include "udp.h"

#define DATA 1

#define ACK 2

#define MAX 16

char IP[MAX];

char hostlocal[MAX];

int config=0;

typedef struct ctrl {

unsigned char type;

unsigned short len;

}CTRL;

typedef struct mssg {

CTRL cntrl;

unsigned char data [1500];

} MSSG;

void recibe(){

UDP canal;

MSSG m;

int i;

struct timeval timer;

fd_set lista_fd;

int ready;

create_UDP (&canal,hostlocal, 8001, IP , 8000);

canal.buffer = (char *)&m;

Page 35: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

35

canal.capacity = sizeof (MSSG);

FD_SET (canal.sockfd, &lista_fd);

timer.tv_sec = 10;

timer.tv_usec = 400000;

ready = select (canal.sockfd+1, &lista_fd, NULL, NULL, &timer);

if (ready > 0 && FD_ISSET (canal.sockfd, &lista_fd)) {

recv_UDP (&canal);

printf ("tipo: %d, len:%d, data: %s\n", m.cntrl.type, m.cntrl.len, m.data);

} else {

printf ("Expiro el temporizador\n");

exit (1);

}

}

void envia(){

UDP canal;

MSSG m;

int i;

create_UDP (&canal, hostlocal, 8000, IP , 8001);

canal.buffer = (char *)&m;

strcpy (m.data, "Este es un mensaje desde el servidor 192.168.10.112");

canal.bytes_to_send = sizeof (CTRL) + strlen (m.data) + 1;

m.cntrl.type = 1;

m.cntrl.len = canal.bytes_to_send;

send_UDP (&canal);

}

void limpia(){

int i;

for(i=0;i<MAX;i++) IP[i]='\0';

}

main(int argc, char *argv[]){

int i=0,bandera=1;

limpia();

strcpy(IP,"192.168.10.111");

Page 36: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

36

strcpy(hostlocal,"192.168.10.112");

while(config!=3){

envia();

recibe();

}

}

}

Estos códigos, utilizan la librerìa UDP.h presentada anteriormente, estos códigos están basados en los sockets presentados anteriormente. El problema de implementar estos sockets, es que hay diferencias de retrasos que logre resolver en función de esperas, pero esta no es la solución óptima, ya que seguirá presentándose problemas de este tipo.

Los siguientes códigos, también están basados en los sockets presentados anteriormente, estos funcionan correctamente, dado esto, implemente la interfaz grafica (basada en el còdigo que mostré en el apartado de ncurses) sobre estos sockets.

11.1. Servidor

/* Estos son los archivos de cabecera usuales */ #include <netdb.h> #include <string.h> #include <stdlib.h> #include <arpa/inet.h> #include <ncurses.h> #define PORT 3150 /* El puerto que será abierto */ #define BACKLOG 2 /* El número de conexiones permitidas */ #define MAX_DATOS 100 #define SIGUE 400 #define FIN 401 #define ANCHO 3 #define ALTO 2 #define COMIENZO 1 #define IZQUIERDA 2 #define DERECHA 3 #define ABAJO 1 #define ARRIBA -1 #define MIN_COORX 5 #define MAX_COORX 79 #define MIN_COORY 0 #define MAX_COORY 19 #define ESPERA 50000

Page 37: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

37

typedef char cadena[MAX_DATOS]; struct Mensaje{ int rotacion; int tipo; int traslacion; int y; }; typedef struct Mensaje msg; int rotacion,traslacion,posy; int recibir_mensaje(int fd,char *buffer); void enviar_mensaje(int fd, char *buffer); void genera_conexion(char *dirección, int *sock); //gcc -o nombre nombre.c -l m -l ncurses WINDOW *create_newwin(int height, int width, int starty, int startx); void destroy_win(WINDOW *local_win); void interfaz(){ WINDOW *my_win; int startx, starty, width=ANCHO, height=ALTO; my_win = create_newwin(height, width, starty, startx); if(rotacion==IZQUIERDA){ startx=MAX_COORX; starty=posy; while(startx>MIN_COORX){ if(starty==MIN_COORY) traslacion = ABAJO; if(starty==MAX_COORY) traslacion = ARRIBA; starty=starty+traslacion; destroy_win(my_win); my_win = create_newwin(height, width, starty,startx--); usleep(ESPERA); } while(startx<MAX_COORX){ if(starty==MIN_COORY) traslacion = ABAJO; if(starty==MAX_COORY) traslacion = ARRIBA; starty=starty+traslacion; destroy_win(my_win); my_win = create_newwin(height, width, starty,startx++); usleep(ESPERA); } rotacion=DERECHA; posy=starty; } destroy_win(my_win); endwin(); }

Page 38: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

38

WINDOW *create_newwin(int height, int width, int starty, int startx){ WINDOW *local_win; local_win = newwin(height, width, starty, startx); box(local_win,0,0); wrefresh(local_win); // Show that box return local_win; } void destroy_win(WINDOW *local_win){ wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); wrefresh(local_win); delwin(local_win); } main(int argc, char **argv){ msg mi_mensaje; char *ip; int lider,valor; int terminar=0; struct sockaddr_in client2; struct hostent *he; int i; WINDOW *my_win; char servidor[MAX_DATOS],buffer[MAX_DATOS],cliente[MAX_DATOS]; int fd, fd2, fd3; /* los archivos descriptores */ struct sockaddr_in server; /* para la información de la dirección del servidor */ struct sockaddr_in client; /* para la información de la dirección del cliente */ int sin_size; /* Se utiliza la llamada socket para abrir un canal birireccional AF_INET: Se utiliza un protocolo tal como TCP o UDP SOCK_STREAM: Indica la semántica para la comunicación, en este ca- so es utilizando un protocolo orientado a conexión. 0: El protcolo a utilizar es seleccionado por el sistema */ if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { printf("error en socket()\n"); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT); /* ¿Recuerdas a htons() de la sección "Conversiones"? =) */ server.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY coloca nuestra dirección IP automáticamente */

Page 39: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

39

//bzero(&(server.sin_zero),8); /* escribimos ceros en el reto de la estructura */ /* A continuación la llamada a bind(). Cuando se crea un conector con socket se le asigna una famila de direcciones pero no una dirección en particular. Bind hace que el conector fd se u- na a la dirección de server. Se utiliza una estructura sockaddr_in debido a que el sockets es de tipo AF_INET */ if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr))==-1) { perror("error en bind"); exit(-1); } /* Indica el servidor que está disponible para recibir BACKLOG conexiones de un conector sd (esto sólo para conectores orientados a conexión)*/ if(listen(fd,BACKLOG) == -1) { /* llamada a listen() */ printf("error en listen()\n"); exit(-1); } sin_size=sizeof(struct sockaddr_in); gethostname(servidor,MAX_DATOS); strcpy(cliente,argv[1]); genera_conexion(cliente,&fd3); mi_mensaje.rotacion=COMIENZO; mi_mensaje.traslacion=ABAJO; mi_mensaje.y=MIN_COORY; mi_mensaje.tipo=SIGUE; enviar_mensaje(fd3,(char *)&mi_mensaje); close(fd3); for(i=0;i<10;i++){ initscr(); refresh(); my_win = create_newwin(22,1,0,4); if ((fd2 = accept(fd,(struct sockaddr *)&client,&sin_size))==-1) { printf("error en accept()\n"); exit(-1); } strcpy(cliente,inet_ntoa(client.sin_addr)); // printf("Se obtuvo una conexión desde %s\n",cliente); recibir_mensaje(fd2,(char *)&mi_mensaje); // sleep(2); // printf("Soy %s y llego el mensaje %d\n",servidor,mi_mensaje.mensaje); rotacion=mi_mensaje.rotacion; traslacion=mi_mensaje.traslacion; posy=mi_mensaje.y;

Page 40: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

40

interfaz(); genera_conexion(cliente,&fd3); mi_mensaje.rotacion=rotacion; mi_mensaje.traslacion=traslacion; mi_mensaje.y=posy; enviar_mensaje(fd3,(char *)&mi_mensaje); close(fd3); } mi_mensaje.tipo=FIN; genera_conexion(cliente,&fd3); enviar_mensaje(fd3,(char *)&mi_mensaje); sleep(2); close(fd); } void genera_conexion(char *direccion, int *sock){ int fd, numbytes; /* Descriptores */ struct hostent *he; /* Estructura que recibirá información sobre el nodo remoto */ struct sockaddr_in server; /* Información sobre la dirección del servidor */ if ((he=gethostbyname(direccion))==NULL){ /* Llamada a gethostbyname() */ printf("gethostbyname() error\n"); exit(-1); } if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1){ /* Llamada a socket() */ printf("socket() error\n"); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr = *((struct in_addr *)he->h_addr); bzero(&(server.sin_zero),8); if(connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1){ /* Llamada a connect() */ printf("connect() error\n"); exit(-1); } *sock=fd; } void enviar_mensaje(int fd, char *buffer){ send(fd,buffer,sizeof(msg),0); } int recibir_mensaje(int fd,char *buffer){ int num_bytes; if ((num_bytes=recv(fd,buffer,sizeof(msg),0)) == -1){

Page 41: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

41

/* Llamada a recv() */ printf("Error en recv() \n"); exit(-1); } return num_bytes; } //gcc -o nombre DOS.c -l m -l ncurses

11.2. Cliente /* Estos son los archivos de cabecera usuales */ #include <netdb.h> #include <string.h> #include <stdlib.h> #include <arpa/inet.h> #include <ncurses.h> #define PORT 3150 /* El puerto que será abierto */ #define BACKLOG 2 /* El número de conexiones permitidas */ #define MAX_DATOS 100 #define SIGUE 400 #define FIN 401 #define ANCHO 3 #define ALTO 2 #define COMIENZO 1 #define IZQUIERDA 2 #define DERECHA 3 #define ABAJO 1 #define ARRIBA -1 #define MIN_COORX 0 #define MAX_COORX 71 #define MIN_COORY 0 #define MAX_COORY 19 #define ESPERA 50000 typedef char cadena[MAX_DATOS]; struct Mensaje{ int rotacion; int tipo; int traslacion; int y; }; typedef struct Mensaje msg;

Page 42: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

42

int rotacion,traslacion,posy; //gcc -o nombre nombre.c -l m -l ncurses WINDOW *create_newwin(int height, int width, int starty, int startx); void destroy_win(WINDOW *local_win); void interfaz(int donde,int direccion,int y){ WINDOW *my_win; int startx,starty; int width=ANCHO,height=ALTO; traslacion=direccion; starty=y; my_win = create_newwin(height, width, starty, startx); if(donde==COMIENZO){ startx=MAX_COORX; while(startx>MIN_COORX){ if(starty==MIN_COORY) traslacion = ABAJO; if(starty==MAX_COORY) traslacion = ARRIBA; starty=starty+traslacion; destroy_win(my_win); my_win = create_newwin(height, width, starty,startx--); usleep(ESPERA); } posy=starty; rotacion=IZQUIERDA; } if(donde==DERECHA){ startx=MIN_COORX; while(startx<MAX_COORX){ if(starty==MIN_COORY) traslacion = ABAJO; if(starty==MAX_COORY) traslacion = ARRIBA; starty=starty+traslacion; destroy_win(my_win); my_win = create_newwin(height, width, starty,startx++); usleep(ESPERA); } while(startx>MIN_COORX){ if(starty==MIN_COORY) traslacion = ABAJO; if(starty==MAX_COORY) traslacion = ARRIBA; starty=starty+traslacion; destroy_win(my_win); my_win = create_newwin(height, width, starty,startx--); usleep(ESPERA); } rotacion=IZQUIERDA; posy=starty; } destroy_win(my_win); endwin(); }

Page 43: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

43

WINDOW *create_newwin(int height, int width, int starty, int startx){ WINDOW *local_win; local_win = newwin(height, width, starty, startx); box(local_win,0,0); wrefresh(local_win); // Show that box return local_win; } void destroy_win(WINDOW *local_win){ wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); wrefresh(local_win); delwin(local_win); } /* El número máximo de datos en bytes */ int recibir_mensaje(int fd,char *buffer); void enviar_mensaje(int fd, char *buffer); void genera_conexion(char *dirección, int *sock); main(){ msg mi_mensaje; char servidor[MAX_DATOS],cliente[MAX_DATOS]; int fd, fd2, fd3; /* los archivos descriptores */ struct sockaddr_in server; /* para la información de la dirección del servidor */ struct sockaddr_in client; /* para la información de la dirección del cliente */ int sin_size; WINDOW *my_win; /* Se utiliza la llamada socket para abrir un canal birireccional AF_INET: Se utiliza un protocolo tal como TCP o UDP SOCK_STREAM: Indica la semántica para la comunicación, en este ca- so es utilizando un protocolo orientado a conexión. 0: El protcolo a utilizar es seleccionado por el sistema */ if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { printf("error en socket()\n"); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT); /* ¿Recuerdas a htons() de la sección "Conversiones"? =) */ server.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY coloca nuestra dirección IP automáticamente */ //bzero(&(server.sin_zero),8); /* escribimos ceros en el reto de la estructura */ /* A continuación la llamada a bind(). Cuando se crea un conector con socket se le asigna una famila de direcciones pero no una dirección en particular. Bind hace que el conector fd se u-

Page 44: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

44

na a la dirección de server. Se utiliza una estructura sockaddr_in debido a que el sockets es de tipo AF_INET */ if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr))==-1) { perror("error en bind"); exit(-1); } /* Indica el servidor que está disponible para recibir BACKLOG conexiones de un conector sd (esto sólo para conectores orientados a conexión)*/ if(listen(fd,BACKLOG) == -1) { /* llamada a listen() */ printf("error en listen()\n"); exit(-1); } sin_size=sizeof(struct sockaddr_in); gethostname(servidor,MAX_DATOS); while(1){ initscr(); refresh(); my_win = create_newwin(22,1,0,74); if ((fd2 = accept(fd,(struct sockaddr *)&client,&sin_size))==-1) { printf("error en accept()\n"); exit(-1); } strcpy(cliente,inet_ntoa(client.sin_addr)); // printf("Se obtuvo una conexión desde %s\n",cliente) recibir_mensaje(fd2,(char *)&mi_mensaje); // printf("Soy %s y llego el mensaje %d dir %d, y %d\n",servidor,mi_mensaje.mensaje,mi_mensaje.direccion,mi_mensaje.y); interfaz(mi_mensaje.rotacion,mi_mensaje.traslacion,mi_mensaje.y); if(mi_mensaje.tipo==SIGUE){ genera_conexion(cliente,&fd3); mi_mensaje.rotacion=rotacion; mi_mensaje.traslacion=traslacion; mi_mensaje.y=posy; enviar_mensaje(fd3,(char *)&mi_mensaje); close(fd3); }else break; } close(fd); } void genera_conexion(char *direccion, int *sock){ int fd; /* Descriptores */ struct hostent *he; /* Estructura que recibirá información sobre el nodo remoto */ struct sockaddr_in server; /* Información sobre la dirección del servidor */ if ((he=gethostbyname(direccion))==NULL){

Page 45: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

45

/* Llamada a gethostbyname() */ printf("gethostbyname() error\n"); exit(-1); } if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1){ /* Llamada a socket() */ printf("socket() error\n"); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr = *((struct in_addr *)he->h_addr); bzero(&(server.sin_zero),8); if(connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1){ /* Llamada a connect() */ printf("connect() error\n"); exit(-1); } *sock=fd; } void enviar_mensaje(int fd, char *buffer){ send(fd,buffer,sizeof(msg),0); } int recibir_mensaje(int fd,char *buffer){ int num_bytes; if ((num_bytes=recv(fd,buffer,sizeof(msg),0)) == -1){ printf("Error en recv() \n"); exit(-1); } return num_bytes; }

Para correr los programas, se utilizan las siguientes instrucciones: El servidor se compila así: gcc -o server sever.c -l m –l ncurses y se ejecuta con ./server

El cliente se compila con: gcc -o cliente cliente.c -l m –l ncurses y se ejecuta con ./client localhost o ./cliente

<IP_servidor>

La única restricción que exige la implementación, es que primero se debe ejecutar el servidor y después el cliente. En caso contrario, la comunicación no se llevara acabo.

La interfaz que desarrolle en pantalla, la presento a continuación:

Page 46: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

46

Page 47: Universidad Autónoma Metropolitana Unidad Iztapalapa ...148.206.53.84/tesiuami/UAMI15434.pdf · servidor y cliente a la vez en la ejecución de las tareas. ... La distancia entre

47

12. Conclusiones La realización de este proyecto, impuso ante mí, grandes retos y obstáculos que en ocasiones, me fue difícil

sacar adelante, recurrí mucho a la investigación y al asesoramiento por parte de maestros. Este proyecto me llena de satisfacción, porque logre cumplir con un gran cometido para mí. En cierta forma, los resultados, no fueron tan satisfactorios como lo hubiera deseado, y creo que gran parte de ello se debe, a la familiarización con los lenguajes que maneje. A pesar de ello, me siento orgulloso de lo logrado, ya que refleja un gran trabajo de investigación que desarrolle en 2 trimestres; inmerso en ciertas ocasiones, de desesperación, y en otras tantas, de alegría.

Este proyecto, abrió mi panorámica, sobre muchas cuestiones, entre las que puedo rescatar, como funcionan los sistemas distribuidos, que función tienen los sockets, como puedo comunicar varias computadoras. Trajo a mi mente nuevos retos, como la implementación de hilos de ejecución, para independizar tareas, y simular un juego completo de ping pong, pero entro en conflicto con las funciones de ncurses.

Hoy finalizo este reporte para su posterior revisión. Agradezco su tiempo y las recomendaciones, que usted me brindo, las facilitaciones prestadas para realizar mi cometido, espero haber logrado cumplir las expectativas que usted esperaba de mi.

13. Referencias virtuales [1] http://wifi.cablesyredes.com.ar/html/standards.htm [2] http://wifi.cablesyredes.com.ar/html/equipamiento.html [3] http://www.virusprot.com/cursos/Redes-Inal%C3%A1mbricas-Curso-gratis2.htm [4] http://wifi.cablesyredes.com.ar/index.html [5] http://foros.toxico-pc.com/showthread.php?t=5262 [6] http://www.configurarequipos.com/doc331.html [7] http://es.wikipedia.org/wiki/Secure_Shell [8] http://www.freebsd.org/doc/es/books/handbook/openssh.html [9] http://es.wikipedia.org/wiki/Ping [10] http://es.wikipedia.org/wiki/User_Datagram_Protocol [11] http://www.chuidiang.com/clinux/sockets/udp/udp.php [12] http://es.wikipedia.org/wiki/Interfaz_de_Paso_de_Mensajes [13] http://crysol.org/es/node/6 [14] http://es.wikipedia.org/wiki/GTK%2B [15] http://es.wikipedia.org/wiki/Ncurses [16] http://es.wikipedia.org/wiki/ Cairo_%28biblioteca%29