Sto scrivendo un server con la libreria asio di boost. Il server gestisce molte connessioni simultanee utilizzando una raccolta di oggetti Connection (una classe wrapper attorno a boost :: asio :: tcp :: socket). All'interno della classe Connection, il socket viene costantemente letto dall'uso di socket.async_read_some (...) e ogni volta che il gestore di lettura viene richiamato con nuovi dati, socket.async_read_some() viene immediatamente richiamato per ulteriori dati da leggere.boost :: asio :: tcp :: socket Chiudi e annulla senza gestori chiamati
Ora, il server può decidere di disconnettere un client per qualche motivo, quindi la cosa naturale da fare è chiamare connection.close() che a sua volta chiama socket.close(), che farà sì che tutte le operazioni asincrone pendenti essere cancellato. Ciò causa l'invocazione del gestore di lettura (associato a un metodo all'interno della connessione di classe) con boost :: asio :: error :: operation_aborted. E il mio problema è: non voglio che ciò accada.
Dopo socket.close(), mi piacerebbe distruggere il socket e la connessione e quindi rimuovere il suo puntatore dall'elenco dei client attivi del server. Tuttavia il gestore di lettura non verrà chiamato fino alla prossima iterazione di io_service.run(), il che significa che non posso distruggere immediatamente il socket o il gestore di lettura che ho passato a socket.async_read_some() fino a quando il gestore non è stato richiamato con il errore. Quindi devo ritardare la distruzione di quegli oggetti in qualche modo; questo è fastidioso.
c'è un modo sicuro per entrambi
- Annulla in attesa di operazioni asincrone senza alcun gestore di da richiamare, in modo da poter distruggere in modo sicuro la presa immediatamente dopo socket.close(), o
- a sapere con certezza quando non è più possibile chiamare altri gestori
O mi sto avvicinando a questo completamente nel modo sbagliato?
Questo suona molto bene. Io sicuramente non uso abbastanza shared_ptr e non sapevo nemmeno di enable_shared_from_questo. Ho usato per fare questo: "socket.async_connect (endpoint, boost :: bind (& Connection :: done_connect, this, _1))", così ora vorrei aggiungere un ulteriore "shared_from_this()" alla chiamata di bind e aggiornare il firma del metodo per un addizionale shared_ptr anche se l'effettivo shared_ptr non verrebbe nemmeno usato nel gestore? Cioè shared_ptr è lì solo per garantire che l'oggetto esista ancora. Sembra giusto? – jlh
Almeno l'ho implementato in questo modo e ora funziona molto bene. Grazie mille! – jlh
@jlh, non è del tutto corretto dire che il parametro shared_ptr "non verrebbe utilizzato nel gestore". Se si associa una funzione membro a shared_ptr, questa viene memorizzata all'interno del raccoglitore (il functor creato con bind()) e de-referenziato sul richiamo del functor. Di conseguenza, il pointee vive finché dura il functor. –