2012-05-16 8 views
6

Piszę serwer z biblioteką asio doładowania. Serwer obsługuje wiele równoczesnych połączeń za pomocą kolekcji obiektów połączeń (klasa otoki wokół boost :: asio :: tcp :: socket). W klasie Connection gniazdo jest stale odczytywane za pomocą socket.async_read_some (...) i zawsze, gdy wywoływacz zostanie wywołany nowymi danymi, socket.async_read_some() jest natychmiast wywoływany ponownie, aby uzyskać więcej danych do odczytania.boost :: asio :: tcp :: socket Zamknij i anuluj bez funkcji obsługi o nazwie

Teraz serwer może z jakiegoś powodu zdecydować o rozłączeniu klienta, więc naturalną rzeczą jest wywołanie metody connection.close(), która z kolei wywołuje socket.close(), co spowoduje, że wszystkie operacje asynchronizacji będą w toku. być anulowane. Powoduje to wywołanie procedury odczytu (powiązanej z metodą w klasie Connection) za pomocą instrukcji boost :: asio :: error :: operation_aborted. A moim problemem jest: nie chcę tego.

Po socket.close(), chciałbym zniszczyć gniazdo i połączenie, a następnie usunąć jego wskaźnik z listy aktywnych klientów serwera. Jednak program obsługi odczytu nie zostanie wywołany do następnej iteracji io_service.run(), co oznacza, że ​​nie mogę natychmiast zniszczyć gniazda lub czytnika obsługi, który przekazałem do socket.async_read_some(), dopóki program obsługi nie zostanie wywołany błąd. Więc muszę jakoś opóźnić zniszczenie tych obiektów; To irytujące.

Czy istnieje bezpieczny sposób zarówno

  • Anuluj toku operacji async bez dowolnego modułu obsługi powoływać, więc mogę bezpiecznie natychmiast zniszczyć gniazdo po socket.close(), lub do
  • bezpiecznie wiesz, kiedy nie więcej osób może być potencjalnie nazwanych

Czy podchodzę do tego całkowicie w niewłaściwy sposób?

Odpowiedz

4

Po zakończeniu operacji async.operation - z powodzeniem lub z błędem - wywoływana jest procedura obsługi zakończenia. Jest to ważna gwarancja i nie sądzę, że dobrym pomysłem jest "zhakowanie" tego zachowania. Problem napotkany w przypadku użycia jest zwykle wywoływany za pomocą metody shared_ptr (shared_from_this idiom): bind shared_ptr<Connection> do procedur obsługi, nie wysyłaj kolejnego async_read po uzyskaniu operation_aborted (lub innego błędu), tak aby po wszystkich procedur obsługi są wykonywane obiekt połączenia jest niszczony za pomocą gniazda.

+0

To brzmi bardzo dobrze. Na pewno nie używam shared_ptr i nawet nie wiem o enable_shared_from_this. Kiedyś to robiłem: "socket.async_connect (punkt końcowy, boost :: bind (& Connection :: done_connect, this, _1))", więc teraz dodałbym dodatkowy "shared_from_this()" do wywołania bind i zaktualizowałbym podpis metody dla dodatkowej shared_ptr, mimo że rzeczywista shared_ptr nie byłaby nawet użyta w module obsługi? To znaczy. shared_ptr jest po to, aby zagwarantować, że obiekt nadal istnieje. Brzmi nieźle? – jlh

+0

Przynajmniej wdrożyłem to w ten sposób i teraz działa bardzo dobrze. Dziękuję Ci bardzo! – jlh

+0

@jlh, to nie do końca słuszne stwierdzenie, że shared_ptr "nie byłby używany w procedurze obsługi". Jeśli bindujesz funkcję member do shared_ptr, jest ona przechowywana w segregatorze (funktor utworzony za pomocą bind()) i odwoływana w wywołaniu funktora. W rezultacie rzecznik żyje tak długo, jak żyje funktor. –

Powiązane problemy