2010-11-16 22 views
10

Napisałem serwer, który nasłuchuje nadchodzących połączeń TCP i klientów łączących się z nim. Kiedy zamykam serwer i uruchamiam go ponownie na tym samym porcie, czasami pojawia się komunikat o błędzie EADDRINUSE podczas wywoływania bind (...) (kod błędu: 98 w systemie Linux). Dzieje się tak, mimo że ustawiam opcję ponownego użycia gniazda.Adres, który jest już używany z akceptorem asio boost

Błąd nie występuje cały czas, ale wydaje się, że zdarza się częściej, gdy klienci są połączeni z serwerem i wysyłają dane podczas zamykania. Chyba problem polega na tym, że nadal są oczekujące połączenia podczas zamykania serwera (temat powiązany: https://stackoverflow.com/questions/41602/how-to-forcibly-close-a-socket-in-time-wait).

Po stronie serwera używam boost :: asio :: ip :: tcp :: acceptor. Inicjuję go opcją "reuse_address" (patrz http://beta.boost.org/doc/libs/1_38_0/doc/html/boost_asio/reference/basic_socket_acceptor.html). Oto fragment kodu:

using boost::asio::ip::tcp; 
acceptor acceptor::acceptor(io_service); 
endpoint ep(ip::tcp::v4(), port); 
acceptor.open(ep.protocol()); 
acceptor.set_option(acceptor::reuse_address(true)); 
acceptor.bind(ep); 
acceptor.listen(); 

Akceptor jest zamknięty:

acceptor.close(); 

Próbowałem też za pomocą acceptor.cancel() wcześniej, ale miał ten sam efekt. Kiedy wystąpił ten błąd, nie mogę ponownie uruchomić serwera na tym samym porcie przez dłuższy czas. Ponowne uruchomienie sieci pomaga, ale nie jest rozwiązaniem trwałym.

Czego mi brakuje?

Każda pomoc będzie bardzo ceniona! :)

+1

Czy twój serwer rozwidla procesy potomne? –

+1

również, czy na pewno gniazdo jest w stanie TIME_WAIT? W takim przypadku możesz chcieć pobrać wyjście 'netstat -ap'. –

+1

Sam, dziękuję bardzo za twój wkład! Pomógł mi znaleźć rozwiązanie mojego problemu. Okazało się, że ustawiłem opcję ponownego użycia adresu dla akceptora, ale nie dla wszystkich innych połączeń. Jeszcze raz bardzo dziękuję za pomoc! – Alexander

Odpowiedz

1

To były pierwotnie komentarz do pytania.


czy Twoje procesy rozwidlenia podrzędnego serwera? Czy na pewno gniazdo jest w stanie TIME_WAIT? Być może zechcesz pobrać dane wyjściowe netstat -ap, gdy tak się stanie

0

Kiedy rozwiązujesz te problemy "na siłę", wydaje się, że wywołujesz problemy na głowie, prawda?

Istnieje powód, dla którego domyślne zachowanie wymaga odczekać, w przeciwnym razie sieć mogłaby na przykład pomylić ACK z poprzedniego połączenia, aby było ACK dla nowego połączenia.

Nie pozwolę, aby to "rozwiązanie" znalazło się w kompilacjach wydań w moim zespole.

Pamiętaj, że gdy prawdopodobieństwo błędu jest bardzo niskie, testowanie jest niezwykle trudne!

+0

Dziękuję za odpowiedź. Podzielam swoją odpowiedź z powodu ograniczeń miejsca. Najpierw podsumuję sytuację: serwer był uruchomiony i słuchał na stałym porcie dla połączeń przychodzących. Następnie klienci podłączeni do niego na tym porcie. W pewnym momencie zatrzymałem serwer, który doprowadził wszystkich klientów do zamknięcia połączenia z serwerem. (Jestem prawie pewien, że poprawnie zamknąłem połączenia zarówno po stronie serwera, jak i po stronie klienta). – Alexander

+0

Następnie ponownie uruchomiłem serwer. Jednak serwer nie mógł rozpocząć nasłuchiwania na tym samym porcie, ponieważ połączenia klientów nie miały opcji ponownego użycia i port był nadal zarezerwowany.Teraz pytanie brzmi, w jaki sposób mogę ponownie wykorzystać adres, który jest już oznaczony w użyciu przez system operacyjny, mimo że wszystkie połączenia zostały poprawnie zamknięte bez użycia opcji ponownego użycia? – Alexander

+3

Akceptacja czekania (która może trwać dość długo) nie jest dopuszczalnym rozwiązaniem dla serwera. Wierzyłem (i nadal wierzę), że ustawienie opcji ponownego użycia jest w tym przypadku odpowiednie. Jednak jestem bardzo zainteresowany alternatywnym rozwiązaniem i byłbym szczęśliwy, gdybyś mógł podać lub wskazać na jedno. (Na marginesie: Proponowane powyżej rozwiązanie działa bardzo dobrze - korzystamy z serwera intensywnie i nie napotkaliśmy żadnych problemów związanych z połączeniami, co oczywiście nie gwarantuje, że jest w 100% wolne od błędów). – Alexander

Powiązane problemy