Piszę serwer proxy oparty na asio boost. W części mojego kodu odpowiedzialnej za przyjmowanie połączeń przychodzących z przeglądarki do serwera proxy, mam do czynienia z zachowaniem, którego nie rozumiem w pełni.boost :: asio :: acceptor - akceptuj nowe połączenia przychodzące, a stare nadal są otwarte
Więc - tworzę obiekt akceptora z kolejnego konstruktora:
_acceptor(_io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), true)
zacząć słuchać tutaj (start_accept):
_new_connection.reset(new connection(*_io_services.front(), _connection_id));
_acceptor.async_accept(_new_connection->get_socket(),
boost::bind(&server::handle_accept, this,
boost::asio::placeholders::error));
i handle_accept
if (!error) {
_new_connection->start();
}
// continue waiting for incoming connections
start_accept();
Ogólnie mój kod akceptowanie połączeń przychodzących jest takie samo jak w przypadku HTTP Server 2 przykład
Problem pojawia się tylko wtedy, gdy pierwsze połączenie przychodzące nie zostało zamknięte, a drugie przychodzenie będzie czekało w kolejce i będzie w toku do momentu, aż pierwsze zostanie zamknięte.
Według tych dwóch odpowiedzi: boost::asio acceptor reopen and async read after EOF
How to launch an "event" when my Boost::asio tcp server just start running (AKA io_service.run())?
Przedmiotem akceptor doda wszystkie połączenia przychodzące w kolejce i nie będzie akceptować je aż do czasu połączenia nie zostaną zamknięte.
Chcę uzyskać natychmiastowe przetwarzanie dla wszystkich połączeń przychodzących - więc nie czekają one w kolejce akceptora, a do tej pory nie znalazłem żadnego rozwiązania.
Czy możesz mi pomóc, jaki jest właściwy sposób realizacji tego?
connection-> start() funkcja
void
connection::start() {
_bsocket.async_read_some(boost::asio::buffer(_bbuffer),
boost::bind(&connection::handle_browser_read_headers,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
));
}
Graphical representation UPDATE: dzienniki Boost ASIO
@asio|1368460995.389629|0*1|[email protected]_accept
@asio|1368461003.855113|>1|ec=system:0
@asio|1368461003.855113|1*2|[email protected]_receive
@asio|1368461003.855113|>2|ec=system:0,bytes_transferred=318
@asio|1368461003.856113|1*3|[email protected]_accept
@asio|1368461003.856113|<1|
@asio|1368461003.856113|2*4|[email protected]_resolve
@asio|1368461003.856113|<2|
@asio|1368461003.866114|>4|ec=system:0,...
@asio|1368461003.866114|4*5|[email protected]_connect
@asio|1368461003.868114|<4|
@asio|1368461004.204133|>5|ec=system:0
@asio|1368461004.204133|5*6|[email protected]_send
@asio|1368461004.204133|<5|
@asio|1368461004.204133|>6|ec=system:0,bytes_transferred=302
@asio|1368461004.204133|6*7|[email protected]_receive
@asio|1368461004.204133|<6|
@asio|1368461004.613156|>7|ec=system:0,bytes_transferred=16384
@asio|1368461004.613156|7*8|[email protected]_send
@asio|1368461004.614157|<7|
@asio|1368461004.614157|>8|ec=system:0,bytes_transferred=16384
@asio|1368461004.614157|8*9|[email protected]_receive
@asio|1368461004.614157|<8|
@asio|1368461004.614157|>9|ec=system:0,bytes_transferred=1946
@asio|1368461004.614157|9*10|[email protected]_send
@asio|1368461004.614157|<9|
@asio|1368461004.614157|>10|ec=system:0,bytes_transferred=1946
@asio|1368461004.614157|10*11|[email protected]_receive
@asio|1368461004.614157|<10|
@asio|1368461004.618157|>11|ec=system:0,bytes_transferred=14080
@asio|1368461004.618157|11*12|[email protected]_send
@asio|1368461004.619157|<11|
@asio|1368461004.619157|>12|ec=system:0,bytes_transferred=14080
@asio|1368461004.619157|12*13|[email protected]_receive
@asio|1368461004.619157|<12|
@asio|1368461019.248994|>13|ec=asio.misc:2,bytes_transferred=0
@asio|1368461019.248994|13|[email protected]
@asio|1368461019.248994|13|[email protected]
@asio|1368461019.248994|<13|
@asio|1368461019.253994|0|[email protected]
@asio|1368461019.253994|>3|ec=system:0
@asio|1368461019.253994|3*14|[email protected]_receive
@asio|1368461019.254994|3*15|[email protected]_accept
@asio|1368461019.254994|<3|
@asio|1368461019.254994|>14|ec=system:0,bytes_transferred=489
@asio|1368461019.254994|14*16|[email protected]_resolve
@asio|1368461019.254994|<14|
@asio|1368461019.281995|>16|ec=system:0,...
@asio|1368461019.281995|16*17|[email protected]_connect
@asio|1368461019.282996|<16|
@asio|1368461019.293996|>17|ec=system:0
@asio|1368461019.293996|17*18|[email protected]_send
@asio|1368461019.293996|<17|
@asio|1368461019.293996|>18|ec=system:0,bytes_transferred=470
@asio|1368461019.293996|18*19|[email protected]_receive
@asio|1368461019.293996|<18|
@asio|1368461019.315997|>19|ec=system:0,bytes_transferred=11001
@asio|1368461019.315997|19*20|[email protected]_send
@asio|1368461019.349999|<19|
@asio|1368461019.349999|>20|ec=system:0,bytes_transferred=11001
@asio|1368461019.349999|20|[email protected]
@asio|1368461019.349999|20|[email protected]
@asio|1368461019.349999|<20|
@asio|1368461019.349999|0|[email protected]
I stwierdził, że zachowanie akceptora zależy od funkcji używam do danych odczytanych z gniazda serwera . klasa połączenia odczytuje dane z przeglądarki, modyfikuje adres URL żądania, łączy się z hostem i wysyła żądanie, następnie odczytuje odpowiedź z serwera i zapisuje ją z powrotem do przeglądarki. Tak więc w momencie, kiedy trzeba czytać ciało serwera - używam tej funkcji
_ssocket.async_read_some(boost::asio::buffer(_sbuffer),
boost::bind(&connection::handle_server_read_body,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
));
Jeśli zawartość długości nie został określony w nagłówkach reakcji serwisu, czytam aż EOF. Jeśli funkcja async_read_some została wywołana i nie ma więcej danych do odczytania na gnieździe, to czeka ~ 15 sekund, zanim podniesiony zostanie EOF. Wszystkie nowe połączenia przychodzące w ciągu 15 sekund nie zostaną zaakceptowane przez akceptanta.
Ale jeśli używam inny wariant async_read -
boost::asio::async_read(_ssocket, boost::asio::buffer(_sbuffer),
boost::bind(&connection::handle_server_read_body,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
));
połączenia przychodzące są akceptowane tylko w porządku.Ale to pobudza :: asio :: async_read działa nieco wolno, czeka na zbieranie danych z gniazda i nie wywołuje obsługi do czasu odczytania danych, więc - myślałem, że określę transfer_at_least
boost::asio::async_read(_ssocket, boost::asio::buffer(_sbuffer), boost::asio::transfer_at_least(1),
boost::bind(&connection::handle_server_read_body,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
));
Tak, stało się lepiej - ale problem z zaakceptowaniem nowych połączeń powraca:/
co jest rzeczywiste różnice - async_read_some i boost :: asio :: async_read - czuje się jak coś jest blokowane.
Czy możesz pokazać kod w funkcji start()? Może blokuje twój kod, więc nie akceptuje() ing. – Bogolt
Zaktualizowałem pytanie. Zasadniczo to sprawdziłem, nie używam żadnych operacji blokowania w klasie połączenia. Z dzienników debugowania widzę, że funkcja serwer :: start_accept została wywołana bezpośrednio po handle_accept. Ale nowe połączenie jakoś nie jest akceptowane przez akceptanta. Zostanie przyjęta tylko wtedy, gdy pierwsza się zamknie. – miks131
Może to jakoś wiąże się z zachowaniem proxy. Używam tego scenariusza do odtworzenia problemu. Czytam odpowiedź z serwera, na którym brakuje nagłówka Content-Lenght. więc używam funkcji async_read_some na gnieździe serwera. Jeśli nie określono długości treści, czytam do momentu, aż EOF zostanie zwrócony. Ostatnie wywołanie funkcji async_read_some na gnieździe serwera, gdy nie ma więcej danych do odczytania, zajmuje długi czas ~ 10 sekund, jeśli nowe połączenie przychodzące pojawi się z przeglądarki do proxy w tym czasie - nie zostanie zaakceptowane przez akceptanta. – miks131