2013-07-03 6 views
9

Niedawno zauważyłem problem z moją aplikacją i myślę, że wynika to z faktu, że nie używam poprawnie boost::asio i nie t zrozumieć, co robi resolver tcp.Różnica między rozwiązywaniem kwerendy i tworzeniem punktu końcowego za pomocą adresu IP i portu (w trybie zwiększania asio)

Zasadniczo używam boost::asio::ip::tcp::resolver do pobierania punktów końcowych do połączenia.

Ostatnio odkryłem, że może on zawierać więcej niż jeden punkt końcowy (w szczególności, gdy łączę się z lokalnym hostem).

W tej chwili proszę o async_connect we wszystkich punktach końcowych. Nie jestem w 100% pewny, ale myślę, że to źle. Powinienem po kolei wysyłać do nich żądanie async_connect, czekać na odpowiedź i spróbować wykonać następną, jeśli i tylko w przypadku niepowodzenia.

Więc w zasadzie wiedząc, że mam dwie możliwości jeśli chcę użyć async_connect na tych punktów końcowych:

  1. byłaby mój kod tak, że mój async_connect awaria uchwyt prawidłowo i na niepowodzenie próby połączenia do innych dostępnych punkt końcowy. Musiałbym wtedy przejść do iteratora punktu końcowego.

  2. Rzuć rozpoznawania nazw i używać końcowego skonstruować sobie tak: boost::asio::ip::tcp::endpoint("localhost", 20015)

I niby mają poczucie, że powinienem użyć pierwsze rozwiązanie i że rezolwer przynosi coś więcej niż ja skonstruowany punkt końcowy.

Ale co przynosi resolwer i jak samoczynnie skonstruowany punkt końcowy sam go rozwiązuje?

Odpowiedz

11

Podczas gdy Sam zwięźle odpowiadał, jak większość aplikacji obsługuje tworzenie punktów końcowych, chciałem rozwinąć resolver.

The resolver służy do konwersji czytelne dla człowieka reprezentacje tekstowe adresu do endpoint (ów), który zawiera uporządkowaną formatu binarnego dla adresu poprzez hostname resolution lub konwersji pomiędzy określonymi reprezentacjami. Na przykład model resolver może rozpoznać odczyt czytelny dla człowieka "localhost" do 0x7F000001 lub przekonwertować "127.0.0.1" na 0x7F000001. Boost.Asio używa lub emuluje getaddrinfo(), aby wykonać tę rozdzielczość. W przypadku rozwiązywania asynchronicznego zostanie utworzony wewnętrzny wątek, który wykona operację.

Z drugiej strony, basic_endpoint nie rozwiązuje się sam. Chociaż nie można go skonstruować za pomocą ciągu i portu, można go zbudować za pomocą ip::address i portu.ip::address może być skonstruowany z ciągu w notacji dziesiętnej (IPv4) albo szesnastkowym (IPv6)

namespace ip = boost::asio::ip; 
ip::tcp::endpoint(ip::address::from_string("127.0.0.1"), 20015); 

Zapewnienie hosta do ip::address::from_string() rzuci wyjątek:

namespace ip = boost::asio::ip; 
ip::address::from_string("localhost"); // throws boost::system::system_error 

Ostatecznie użyj:

  • resolver, jeśli chcesz obsługiwać rozpoznawanie nazw hostów lub konwersje IP. Jest to szczególnie wygodne, gdy adresy IP mogą się zmieniać, ale nazwy hostów pozostają takie same lub gdy pojedyncza nazwa hosta może zostać przetłumaczona na wiele adresów IP.
  • ip::address::from_string(), aby utworzyć adres z adresu IP.
4

Masz rację, że połączenie ze wszystkimi punktami końcowymi zwróconymi z operacji rozstrzygnięcia nie jest prawdopodobne, czego oczekuje twoja aplikacja. Wybór nr 2 nie zadziała, ponieważ nie ma konstruktora dla basic_endpoint(const char*, int). Wybór # 1 to sposób, w jaki zbudowano kilka przykładów Asio, w szczególności async tcp client demonstrating timeouts.

Refaktoryzacja kodu w celu włączenia endpoint_iterator zwróconego z programu tłumaczącego nie powinna być zbyt trudna, postępuj zgodnie z powyższym przykładem, jeśli masz problemy. Zauważ, że używa blokowania resolve(), a nie async_resolve(), koncepcja jest jednak taka sama.

+1

Dzięki za odpowiedź, jest to bardzo pomocne. Dowiedziałem się jednak, że użycie async resolve było błędne (moja platforma to okno i dość często uzyskuje się błąd "WSA_OPERATION_ABORTED" '995'). Dlatego zdecydowałem się na rozwiązanie pośrednie z synchronicznym rozwiązaniem i iteracyjnym asynchronicznym połączeniem na każdym punkcie końcowym, a tak, refaktoryzacja mojego kodu była łatwa. – Arthur

Powiązane problemy