Main logo La Página de DriverOp

Capítulo 14. Un problema del mundo real, y su solución.

En este capítulo:

El problema.

En los últimos años he estado escribiendo un raytracer distribuido. Este utiliza TCP/IP para enviar descripciones de las escenas que se renderizarán a través de una red desde un servidor central a un grupo de clientes. Los clientes renderizan la imagen, y después devuelven los datos al servidor. Algunos beta testers estaban interesados en probar el programa, pero mencionaron que no tenian el protocolo TCP/IP en su máquina. Decidí que sería útil escribir cierto código que emulara los seckets TCP, permitiendo la comunicación entre dos aplicaciones (cliente y servidor) en la máquina local.

Varias soluciones potenciales fueron investigadas. La más prometedora al principio parecía ser usar cañerías con nombre (named pipes). Desafortunadamente surgió un problema: Los protocolos que estaba usando encima de TCP/IP asumian que la semántica de la conexión se podía realizar en base a conexiones punto-a-punto (peer-to-peer): cualquier programa podría iniciar una conexión con la otra, y cualquier programa podría desconectarse en cualquier momento. La conexión y desconexión eran perfectamente simétricas: Los protocolos usados encima de TCP realizaban tres formas de inicialización encima de aquella realizada en la capa TCP para negociar si una conexión podría ser cerrada, y si eso ocurría, cualquier extremo podría cerrar la conexión. Desafortunadamente, las cañerias con nombre, no proporcionaban la semántica correcta para la desconexión, y no se las arreglaban bién frente a varias situaciones de error.

La solución.

No tengo la intención de explicar la solución detalladamente, pero lectores más avanzados pueden encontrar interesante la lectura del código. Al final, decidí utilizar memoria compartida para la transferencia de datos, y poner toda la sincronización desde el principio. La solución fue implementada en 3 etapas.

  • Una DLL fue escrita la cual proporcionó una cañería bloqueante bidireccional entre las dos aplicaciones.
  • Se escribieron dos hilos, uno lector y otro escritor, para permitir el acceso asincrónico a las cañerías bloqueantes.
  • Una envoltura alrededor de los hilos fue escrita para proporcionar un interfaz asincrónico similar a los sockets nonblocking.

Los archivos de la DLL y de interfaz.

Este DLL es similar al ejemplo de buffer limitado que se encuentra en el capítulo 9. Volviendo a ver este código, puedo presumir solamente que lo debí escribír después de un par de semanas de hackear freneticamente con el C en el trabajo, porque está mucho más revuelto de lo que necesita ser. Un punto de interés es que los semáforos usados para bloquear operaciones no asumen que los buffers limitados son de cualquier tamaño en particular; en lugar de eso el estado se mantiene si los hilos lector o escritor están bloqueados o no.

Los hilos lectores y escritores.

Los hilos de la cañería son exactamente análogos a los hilos lector y escritor en el BAB del capítulo 10. Las notificaciones no se utilizan para operaciones de escritura, en lugar de eso, el hilo escritor almacena temporariamente los datos internamente. Esto era permisible dado la semántica de protocolos de capa más altos.

Una interfaz basada en sockets.

Esta es una interfaz de sockets no muy pura, y debe ser razonablemente obvio a esos familiarizados con la programación de sockets de TCP. Puesto que esta implementación fue diseñada para trabajar específicamente con otros protocolos que escribí, es valioso incluyendo la capa de transacción de los protocolos sobrepuestos así que usted puede ver cómo encaja el socket dentro del en el esquema de cosas.

Martin Harvey -