Przykłady, o których wspominasz w dokumentacji Boost.Asio, są całkiem niezłe, aby zobaczyć, jak działają. Masz rację, że początkowo może to wydawać się nieco trudne do zrozumienia, szczególnie jeśli nie znasz tych pojęć. Zalecam jednak, aby zacząć od przykładu serwera czatu i uzyskać go na swoim komputerze. Pozwoli to bliżej przyjrzeć się wszystkim i zacząć zmieniać rzeczy, aby dowiedzieć się, jak to działa. Pozwól, że poprowadzę Cię przez kilka rzeczy, które uważam za ważne, aby zacząć.
Z Twojego opisu wynika, że serwer czatu daje dobry punkt wyjścia, ponieważ ma już podobne elementy, których potrzebujesz. Posiadanie serwera asynchronicznego jest tym, czego potrzebujesz, ponieważ wtedy możesz łatwo obsłużyć wielu klientów z jednym wątkiem. Od samego początku nic zbyt skomplikowanego.
Uproszczony, asynchroniczny w tym przypadku oznacza, że serwer działa poza kolejką, pobierając procedurę obsługi (zadanie) i wykonuje ją. Jeśli nie ma nic w kolejce, po prostu czeka na coś, co zostanie umieszczone w kolejce. W twoim przypadku oznacza to, że może to być połączenie od klienta, nowe odczytanie wiadomości od klienta lub coś podobnego. Aby to zadziałało, należy skonfigurować każdy program obsługi (funkcję obsługującą reakcję na określone zdarzenie).
Pozwól mi wyjaśnić trochę za pomocą kodu z przykładu serwera czatu.
W klasie server source file widać klasę chat_server
, która wywołuje start_accept
w konstruktorze. Tutaj konfiguruje się moduł akceptujący.
void start_accept()
{
chat_session_ptr new_session(new chat_session(io_service_, room_)); // 1
acceptor_.async_accept(new_session->socket(), // 2
boost::bind(&chat_server::handle_accept, this, new_session, // 3
boost::asio::placeholders::error)); // 4
}
Linia 1: a chat_session
obiekt jest tworzony co stanowi jedną sesję między klientem a serwerem. Sesja jest tworzona dla akceptacji (żaden klient jeszcze się nie połączył).
Linia 2: asynchroniczny przyjąć do gniazdka ...
Linia 3 ... związany zadzwonić chat_server::handle_accept
kiedy to się stanie. Sesja jest przekazywana do wykorzystania przez pierwszego klienta, który się łączy.
Teraz, gdy patrzymy na handle_accept
widzimy, że po połączeniu się z klientem wywoływana jest sesja start
(po prostu uruchamia się rzeczy między serwerem a tym klientem).Wreszcie, nowa akceptacja jest znakomita, jeśli inni klienci również chcą się połączyć.
void handle_accept(chat_session_ptr session,
const boost::system::error_code& error)
{
if (!error)
{
session->start();
}
start_accept();
}
To jest to, co chcesz również mieć. Znakomita akceptacja dla połączeń przychodzących. A jeśli wielu klientów może się połączyć, zawsze powinno być jedno z nich, tak aby serwer mógł obsłużyć akceptację.
Sposób interakcji serwera i klienta (ów) znajduje się w sesji i można wykonać ten sam projekt i zmodyfikować go, aby zrobić to, co chcesz. Wspomniałeś, że serwer musi patrzeć na to, co jest wysyłane i robić różne rzeczy. Spójrz na chat_session
i funkcję start
, która została wywołana przez serwer w handle_accept
.
void start()
{
room_.join(shared_from_this());
boost::asio::async_read(socket_,
boost::asio::buffer(read_msg_.data(), chat_message::header_length),
boost::bind(
&chat_session::handle_read_header, shared_from_this(),
boost::asio::placeholders::error));
}
Ważne jest połączenie pod numer boost::asio::async_read
. Tego też chcesz. Zapewnia to znakomity odczyt na gnieździe, dzięki czemu serwer może odczytać, co wysyła klient. Istnieje funkcja obsługi (funkcja), która jest związana z tym zdarzeniem chat_session::handle_read_header
. Będzie to wywoływane za każdym razem, gdy serwer odczyta coś na gnieździe. W tej funkcji obsługi możesz zacząć umieszczać swój kod, aby określić, co zrobić, gdy zostanie wysłana określona wiadomość i tak dalej.
Ważne jest, aby podczas wywoływania asynchronicznych funkcji boost :: asio rzeczy nie występowały w tym wywołaniu (tzn. Gniazdo nie zostanie odczytane, jeśli wywołasz funkcję odczytaną). To jest aspekt asynchroniczny. Po prostu rejestrujesz coś, a twój kod jest wywoływany, gdy tak się dzieje. Dlatego, gdy ten odczyt zostanie wywołany, natychmiast zwróci się i wrócisz do serwera (jeśli podążysz za tym, jak się nazywają). A jeśli pamiętasz, nazywamy również start_accept
, aby skonfigurować inną akceptację asynchroniczną. W tym momencie masz dwa wyjątkowe programy obsługi oczekujące na połączenie z innym klientem lub na pierwszym kliencie, który coś wysyła. W zależności od tego, co dzieje się najpierw, ten konkretny moduł obsługi zostanie wywołany.
Ważne jest również zrozumienie, że za każdym razem, gdy coś jest uruchomione, działa nieprzerwanie, dopóki nie zostanie wykonane wszystko, co musi zrobić. Inne programy obsługi muszą poczekać, nawet jeśli istnieją wyjątkowe zdarzenia, które je wyzwalają.
Wreszcie, aby uruchomić serwer, musisz mieć io_service
, który jest centralnym pojęciem w Asio.
io_service.run();
To jest jedna linia, którą można zobaczyć w funkcji main
. To właśnie mówi, że wątek (tylko jeden w przykładzie) powinien uruchomić usługę io, która jest kolejką, w której procedury obsługi są zapisywane, gdy jest praca do wykonania. Gdy nic, usługa io_ tylko czeka (oczywiście blokując główny wątek).
Mam nadzieję, że pomoże ci to zacząć od tego, co chcesz robić. Jest wiele rzeczy, które możesz zrobić i rzeczy do nauki. Uważam to za świetny kawałek oprogramowania! Powodzenia!
Pozdrawiamy dzięki. Masz rację, naprawdę muszę je przegryźć. Jedną z rzeczy, której nie rozumiem, jest silne wykorzystanie wspólnych wskaźników w przykładach. Gdzie są przechowywane? Magicznie w asio? Jeśli połączenie zginie, czy zostaną automatycznie wyczyszczone? Dzięki – Cookie
Używanie współdzielonych wskaźników polega na utrzymywaniu pewnych obiektów przy życiu "wewnątrz" uchwytów. Asio ma jedynie handler (funkcja pobrana od boost :: bind) i tam jest powiązany wspólny wskaźnik. W ten sposób obiekt w udostępnionym wskaźniku jest utrzymywany przy życiu tak długo, jak żyje przewodnik, co jest ważne. Sesja jest przekazywana do wszystkich kryteriów boost: bind as shared_from_this() w klasie sesji, co jest całkiem fajne, ponieważ całe życie należy do asynchronicznych procedur obsługi przez cały czas, które tak będą obsługiwać czyszczenie w przypadku błąd. – murrekatt