2013-05-13 16 views
7

Sto scrivendo server proxy basato su boost asio. Nella parte del mio codice responsabile dell'accettazione delle connessioni in entrata dal browser al server proxy, sto affrontando il comportamento che non sono completamente comprensibile.boost :: asio :: acceptor - accetta nuove connessioni in entrata mentre quelle vecchie sono ancora aperte

Così - Sto creando oggetto di accettazione con la prossima costruttore:

_acceptor(_io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), true) 

iniziare ad ascoltare qui (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)); 

e handle_accept

if (!error) { 
    _new_connection->start(); 
} 

// continue waiting for incoming connections 
start_accept(); 

In generale il mio codice per accettare le connessioni in entrata è lo stesso come nell'esempio HTTP Server 2

Il problema si verifica solo quando la prima connessione in ingresso non è stata chiusa, quindi il secondo in entrata verrà messo in coda e in attesa, fino a quando il primo verrà chiuso.

Secondo questi due risposte: 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())?

L'oggetto accettatore aggiungerà tutte le connessioni in entrata nella coda e non accetterà loro fino in attesa di connessione non verrà chiusa.

Voglio ottenere l'elaborazione immediata per tutte le connessioni in ingresso, quindi non sono in attesa nella coda dell'accettatore e non ho trovato alcuna soluzione fino ad ora.

Potrebbe aiutarmi, qual è il modo giusto per implementarlo?

connection-> start() funzione

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: Boost tronchi 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] 

ho scoperto che il comportamento di accettore dipende da funzioni che sto usando per i dati letti dal socket server . la classe di connessione legge i dati dal browser, modifica l'URL della richiesta, si connette all'host e invia la richiesta, quindi legge la risposta dal server e la scrive sul browser. Quindi nel momento in cui ho bisogno di leggere il corpo del server - Io uso questa funzione

_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 
     )); 

Se lunghezza del contenuto non è stato specificato nelle intestazioni di risposta di servizio, sto leggendo fino EOF. Se è stata chiamata la funzione async_read_some e non ci sono più dati da leggere sul socket, è in attesa di ~ 15 secondi prima che EOF venga generato. Tutte le nuove connessioni in entrata durante questo 15 sec non saranno accettate dall'accettatore.

Ma se sto usando un'altra variante del 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 
     )); 

connessioni in entrata vengono accettate bene.Ma potenzia: asio :: async_read funziona un po 'lento, aspetta che vengano letti dati dal socket e non chiama handler fino a che i dati non saranno letti, quindi - ho pensato di specificare 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 
     )); 

Sì, è diventato migliore - ma il problema con l'accettazione di nuove connessioni rendimenti:/

ciò che è reale differenza tra - async_read_some e boost :: ASIO :: async_read - ci si sente come qualcosa è bloccato.

+1

È possibile visualizzare il codice all'interno della funzione start()? Forse sta bloccando il tuo codice, quindi non accetta accept() ing. – Bogolt

+0

Ho una domanda aggiornata. In generale ho controllato questo, non uso alcuna operazione di blocco nella classe di connessione. E dai registri di debug vedo che la funzione server :: start_accept è stata chiamata immediatamente dopo handle_accept. Ma la nuova connessione in qualche modo non è accettata da acceptor. Sarà accettato solo quando il primo verrà chiuso. – miks131

+0

Forse è collegato al comportamento del proxy in qualche modo. Sto usando questo scenario per riprodurre il problema. Sto leggendo la risposta dal server che manca l'intestazione Content-Lenght. quindi sto usando la funzione async_read_some su un socket del server. Se la lunghezza del contenuto non è specificata, sto leggendo finché non verrà restituito EOF. L'ultima chiamata della funzione async_read_some sul socket del server, quando non ci sono più dati da leggere richiede molto tempo ~ 10 sec, se la nuova connessione in arrivo appare da browser a proxy durante quel periodo - non sarà accettata da acceptor. – miks131

risposta

0

Non so se questo aiuterà, ma nel mio server, sto usando il seguente per la mia sessione di lettura richiesta:

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)); 

Ho poi discarica qualsiasi cosa ricevo in un parser per assicurare che si tratta di sano (stato di gestione, ecc.).

Altrimenti, credo che sto facendo tutto quello che stai facendo, basandomi su quello che vedo qui.

Se questo funziona, sembrerebbe che asio abbia un comportamento non intuitivo.