Reputation: 208
I'm writing proxy server based on boost asio. In the part of my code responsible for accepting incoming connections from browser to proxy server, I'm facing the behaviour i'm not fully understand.
So - I'm creating acceptor object with next constructor:
_acceptor(_io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port ), true)
start listening here (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));
and handle_accept
if (!error) {
_new_connection->start();
}
// continue waiting for incoming connections
start_accept();
In general my code for accepting incoming connections is the same as in the HTTP Server 2 example
The problem appears only when first incoming connection was not closed, then second incoming will be queued and pending, till first one will be closed.
According to this two answers: 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() )?
The acceptor object will add all incoming connections into the queue and will not accept them till pending connection will not be closed.
I want to achieve immediate processing for all incoming connections - so they are not pending in the acceptor's queue, and I did not find any solution so far.
Could you please help me, what is right way to implement this?
connection->start() function
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 asio logs
@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 found that acceptor's behaviour depends on functions I'm using for read data from server socket. connection class reads data from browser, modifies request url, connects to host and sends request, then reading response from server and writing it back to browser. So at the moment when I need to read server body - I use this function
_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
));
If content-length was not specified in service response headers, I'm reading till EOF. If async_read_some function was called and there is no more data to read on socket it's waiting ~15 sec before EOF will be raised. All new incoming connections during this 15 sec will not be accepted by acceptor.
But if I'm using another variant of 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
));
Incoming connections are accepted just fine. But it boost::asio::async_read works a bit slow, it is waiting for bunch of data to be read from socket and does not call handler till that data will be read, so - I thought I will specify 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
));
Yep, it became better - but problem with accepting new connections returns :/
What is real differences between - async_read_some and boost::asio::async_read - it feels like something is blocked.
Upvotes: 7
Views: 5905
Reputation: 109
I do not know if this will help, but in my server, I'm using the following for my session's read request:
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 then dump anything I receive into a parser to ensure that it's sane (handling state, etc).
Otherwise, I believe I am doing everything you're doing, based on what I see here.
If this works, then it would seem asio has behavior that isn't intuitive.
Upvotes: 0