2013-05-13 8 views
7

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.

+1

Czy możesz pokazać kod w funkcji start()? Może blokuje twój kod, więc nie akceptuje() ing. – Bogolt

+0

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

+0

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

Odpowiedz

0

Nie wiem, czy to pomoże, ale na moim serwerze, używam następujących dla mojego sesja Przeczytajmy żądanie:

boost::asio::async_read(socket(), boost::asio::buffer(_incoming), 
    boost::asio::transfer_at_least(1), 
    boost::bind(&server_class::handle_read, shared_from_this(), 
     boost::asio::placeholders::error, 
     boost::asio::placeholders::bytes_transferred)); 

I wtedy zrzucić cokolwiek I przyjmij do parsera aby upewnić się, że jest to rozsądny (stan postępowania, itp.).

W przeciwnym razie wierzę, że robię wszystko, co robisz, na podstawie tego, co tu widzę.

Jeśli to zadziała, to wydaje się, że tak samo zachowanie nie jest intuicyjne.