2012-09-03 23 views
5

Utilizo el mismo socket en mi servidor udp para recibir datos de clientes en algún puerto, y más tarde después de que el procesamiento de solicitudes responda a clientes usando ip :: ud :: socket :: async_send_toUse el mismo socket udp para async receive/send

La recepción se realiza de forma asíncrona con async_receive_from también. El socket usa el mismo ioService (es el mismo socket después de todo) La documentación no indica claramente si se puede tener en un momento el mismo socket udp para recibir datagramas del cliente A (en modo asíncrono) y posiblemente enviar otro datagrama al cliente B (async enviado) al mismo tiempo Sospecho que esto podría ocasionar problemas. Terminé usando el mismo socket para responder porque no pude vincular otro socket al mismo puerto del servidor mientras respondía a otro cliente.

¿Cómo puedo vincular otro socket al mismo puerto de servidor?

EDIT. Trato de obligar a la segunda toma de UDP al mismo puerto UDP con:

socket(ioService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)) 

Cuando hago esto por primera vez (vinculante para el servidor de "recepción" socket) que está bien, pero tratando de crear otro toma la segunda vez como la informa el error en el enlace (asio arroja la excepción)

+2

Por favor, especifique su pregunta real. ¿Está funcionando su configuración y está buscando confirmación de que está bien por diseño? ¿O no está funcionando, y si no es qué error observas? ¿O está preguntando cómo enlazar otro socket al puerto del servidor? – mtrw

+0

@mtrw ¿Es posible enlazar otro socket al mismo puerto de servidor? De esa manera usaría diferentes enchufes para enviar repeticiones. Lo que ocurre es que creo que mi configuración puede causar un mal funcionamiento del servidor. – Ghita

+0

Por favor, edite su pregunta para aclarar en lugar de agregar comentarios –

Respuesta

14

Es posible tener un socket UDP recibiendo simultáneamente desde un punto extremo remoto y enviando a un punto final remoto diferente. Sin embargo, según la documentación de Boost.Asio Threads and Boost.Asio, generalmente no es seguro realizar llamadas simultáneas en un solo objeto.

Por lo tanto, esto es seguro:

 thread_1        | thread_2 
--------------------------------------+--------------------------------------- 
socket.async_receive_from(...);  | 
socket.async_send_to(...);   |

y esto es seguro:

 thread_1        | thread_2 
--------------------------------------+--------------------------------------- 
socket.async_receive_from(...);  | 
             | socket.async_send_to(...);

pero esto se especifica como no estar segura:

 thread_1        | thread_2 
--------------------------------------+--------------------------------------- 
socket.async_receive_from(...);  | socket.async_send_to(...); 
             |

Tenga en cuenta que algunas funciones , como boost::asio::async_read, son operación compuesta, y tiene restricciones de seguridad de hilos adicionales.


Si cualquiera de lo siguiente es cierto, entonces no hay sincronización adicional tiene que ocurrir, ya que el flujo será implícitamente síncrono:

  • Todas las llamadas de socket se producen dentro de los manipuladores, y io_service::run() solamente se invoca desde un solo hilo.
  • async_receive_from y async_send_to solo se invocan dentro de la misma cadena de operaciones asincrónicas. Por ejemplo, el ReadHandler pasado a async_receive_from invoca async_send_to, y el WriteHandler pasado a async_send_to invoca async_receive_from.

    void read() 
    { 
        socket.async_receive_from(..., handle_read); --. 
    }             | 
        .-----------------------------------------------' 
        |  .----------------------------------------. 
        V  V          | 
    void handle_read(...)        | 
    {             | 
        socket.async_send_to(..., handle_write); --. | 
    }            | | 
        .-------------------------------------------' | 
        |            | 
        V            | 
    void handle_write(...)       | 
    {             | 
        socket.async_receive_from(..., handle_read); --' 
    } 
    

Por otro lado, si hay varios hilos que hacen potencialmente llamadas simultáneas a la toma de corriente, entonces la sincronización tiene que ocurrir.Considere realizar la sincronización al invocar las funciones y los controladores a través de boost::asio::io_service::strand, o mediante el uso de otros mecanismos de sincronización, como Boost.Thread's mutex.


Además de la seguridad de la rosca, debe tenerse en cuenta la gestión de la vida útil de los objetos. Si el servidor necesita procesar solicitudes múltiples al mismo tiempo, tenga cuidado con la propiedad de buffer y endpoint para cada cadena request-> process-> response. Según la documentación de async_receive_from, la persona que llama conserva la propiedad del buffer y endpoint. Como tal, puede ser más fácil administrar la vida útil de los objetos a través del boost::shared_ptr. De lo contrario, si la cadena es lo suficientemente rápida como para no requerir cadenas concurrentes, simplifica la administración, permitiendo que se utilice el mismo buffer y endpoint por solicitud.


Finalmente, la clase socket_base::reuse_address permite una toma en obligarse a una dirección que ya está en uso. Sin embargo, no creo que es una solución aplicable en este caso, ya que se utiliza generalmente:

  • Para TCP para permitir un proceso para reiniciar y escuchar al mismo puerto, incluso si el puerto está en un estado TIME_WAIT.
  • Para que UDP permita que varios procesos se vinculen al mismo puerto, permitiendo que cada proceso reciba y difunda a través de multidifusión.
+0

Bastante una respuesta impresionante. En mi caso, como dije solo un hilo de servicio (principal), aunque async_receive_from/async_send_to no se puede llamar intercalado, uno de ellos puede invocarse antes de que el otro se haya completado (el controlador completo para el otro llamado). Esto es porque hago el procesamiento así dicho en otro hilo que tiene que ver con el hilo ioService. – Ghita

+0

Otra cosa. Dónde se especifica que las clases de puntos finales deben manejarse de una manera particular. Una vez que recibo un punto final como parámetro de salida en async_receive_from hago copias de él (usando el constructor de copias) pasándolo como un "estado" (para que sepa a dónde responder más adelante) hasta el momento en que necesito devolver la respuesta. – Ghita

+2

Está bien tener múltiples operaciones asíncronas pendientes en un objeto; solo se especifica que las llamadas concurrentes al objeto no son seguras. Si las llamadas de socket se están produciendo desde fuera de un controlador y solo un hilo está invocando 'io_service :: run()', la publicación de las llamadas de socket en 'io_service' se sincronizará. Aumentar.Asio requiere que quien llama garantiza que ciertos argumentos seguirán siendo válidos hasta que se llame al controlador; nunca obliga al usuario a administrarlos de una manera específica. En algunos casos, puede ser más fácil asociar la vida útil de los objetos a la cadena de sincronización a través de punteros inteligentes. –

Cuestiones relacionadas