Estoy escribiendo un servidor con la biblioteca asio de boost. El servidor maneja muchas conexiones simultáneas utilizando una colección de objetos Connection (una clase contenedora alrededor de boost :: asio :: tcp :: socket). Dentro de la clase Connection, el socket se lee constantemente utilizando socket.async_read_some (...) y cada vez que se invoca el manejador de lectura con datos nuevos, se llama inmediatamente a socket.async_read_some() para que se lean más datos.boost :: asio :: tcp :: socket Cierre y cancele sin llamar a los controladores
Ahora, el servidor puede decidir desconectar un cliente por algún motivo, por lo que lo más lógico es llamar a connection.close() que a su vez llama a socket.close(), lo que provocará que todas las operaciones asincrónicas pendientes ser cancelado Esto hace que el controlador de lectura (vinculado a un método dentro de la clase Connection) se invoque con boost :: asio :: error :: operation_aborted. Y mi problema es: no quiero que esto suceda.
Después de socket.close(), me gustaría destruir el socket y la conexión y luego quitar su puntero de la lista de clientes activos del servidor. Sin embargo, el controlador de lectura no se invocará hasta la próxima iteración de io_service.run(), lo que significa que no puedo destruir inmediatamente el socket o el controlador de lectura que pasé a socket.async_read_some() hasta que se haya invocado el controlador con el error. Así que tengo que retrasar la destrucción de esos objetos de alguna manera; eso es molesto.
¿Existe una forma segura de cualquiera
- Cancelar las operaciones pendientes asincrónicos sin ningún controlador que se debe invocar, por lo que puede destruir de manera segura la toma inmediatamente después de Socket.close(), o
- a saber con seguridad cuándo no se pueden llamar potencialmente más manipuladores
¿O me estoy acercando a esto completamente de la manera incorrecta?
Esto suena muy bien. Seguro que no uso shared_ptr lo suficiente y ni siquiera sabía sobre enable_shared_from_this. Solía hacer esto: "socket.async_connect (endpoint, boost :: bind (& Connection :: done_connect, this, _1))", así que ahora solo agregaría un adicional "shared_from_this()" a la llamada de enlace y actualizar el ¿firma de método para un shared_ptr adicional aunque el shared_ptr real ni siquiera se usaría en el controlador? Es decir. el shared_ptr está ahí para garantizar que el objeto aún exista. Suena bien? – jlh
Al menos lo implementé de esta manera y funciona muy bien ahora. ¡Muchas gracias! – jlh
@jlh, no es del todo correcto decir que shared_ptr "no se usaría en el controlador". Si vincula una función de miembro a shared_ptr, se almacena dentro de la carpeta (el functor creado con bind()), y se le quita la referencia en la invocación de functor. Como resultado, el pointee vive mientras el functor viva. –