Re: [asio-users] accept: asio vs BSD
Brought to you by:
chris_kohlhoff
From: Matt G. <mat...@jc...> - 2018-12-28 22:47:34
|
The other thing I don’t understand is why you’re accepting an integer port number, as a constructor parameter of TcpConnection. Now that I’m looking at the reference docs of async_accept(), I don’t see any version which initializes an integer port number. You must be going out of your way to get that? Or are you passing in the same port that the acceptor is listening on? The former is unnecessary, while the latter is incorrect. I would pass the socket you’re modifying with async_accept() to TcpConnection::TcpConnection(). Also, please post more complete code snippets, so we don’t have to play unnecessary guesswork. Matt From: Matt Gruenke Sent: Friday, December 28, 2018 17:29 To: 'je...@p2...' <je...@p2...> Subject: RE: [asio-users] accept: asio vs BSD Some code appears to be missing. In the lambda in TcpServer::Accept(), you’re calling ReceiveHeader(), although that’s a member function of TcpConnection. It seems like there should be some code which constructs a new TcpConnection instance (probably also adding it to a pool) and calls ReceiveHeader() on it. Matt From: Jeff Abrahamson [mailto:je...@p2...] Sent: Friday, December 28, 2018 17:14 To: asi...@li...<mailto:asi...@li...> Subject: [asio-users] accept: asio vs BSD I'm chasing a strange bug (linux, ubuntu 16.04) in which a server sometimes complains that it is listening on an invalid socket. (Sometimes this code runs ok.) What I can see is that it listens, and before anyone can connect, it thinks it successfully accepted, tries to read, and hits an error: system:9 bad file descriptor. So I agree with the error, I just don't understand why the accept succeeds. [Note: you can skip the code, the real question is below.] Now what I'm doing seems straight-forward: I create an io_service object, construct a class that just holds the necessary objects for communication, that class calls async_accept(), and when that succeeds it calls async_read(). This is all happening on a highly quiescent vm, so I'm pretty sure nothing else is going on behind my back. I've pared the code down so that it really isn't doing anything other than this at this point. My real question is below the code, but I'm sharing the code pro forma and in the hopes that, as often happens, in preparing this question and cleaning extraneous cruft from the code I'll solve my problem myself and so delete the mail. boost::asio::io_service io_service; TcpServer tcp(io_service, port, [](const string& message) -> string { ... }); io_service.run(); TcpServer::TcpServer(boost::asio::io_service& io_service, const int port, const TcpReceiveCallback& callback) : TcpConnection(io_service, port, callback), acceptor_(io_service_, boost::asio::ip::tcp::endpoint(tcp::v4(), port)), server_connection_state_(TcpServerNotConnected), server_reconnect_delay_(1) { Accept(); } TcpConnection::TcpConnection(boost::asio::io_service& io_service, const int port, const TcpReceiveCallback& callback) : io_service_(io_service), port_(port), socket_(io_service_), dead_(false), error_count_(0), scheduler_(io_service), callback_(callback) {} void TcpServer::Accept() { LOGGABLE; LOG_INFO << "Accept requested."; server_connection_state_ = TcpServerAcceptWait; acceptor_.async_accept(socket_, [this](boost::system::error_code ec) { LOGGABLE; if (ec) { LOG_WARNING << "TcpServer failed to accept on socket: " << AsioError(ec) << " (delay=" << server_reconnect_delay_ << " seconds)"; if (server_reconnect_delay_ < 60) { // Exponential backoff, capped at 64 seconds. server_reconnect_delay_ *= 2; } scheduler_.AddTask("Accept", [this]() { return Accept(); }, server_reconnect_delay_, true); return; } server_connection_state_ = TcpServerConnected; LOG_INFO << "Accepting."; ReceiveHeader(); }); } void TcpConnection::ReceiveHeader() { LOGGABLE; if (dead_) { LOG_INFO << "TcpConnection::ReceiveHeader(): but we're dead."; return; } // receive_buffer_.clear(); boost::asio::async_read( socket_, boost::asio::buffer(receive_buffer_, kTcpHeaderSize), boost::asio::transfer_exactly(kTcpHeaderSize), [this](boost::system::error_code ec, std::size_t received_length) { LOGGABLE; if (ec) { LOG_WARNING << "Header read error: " << AsioError(ec); // ... } // ... ReceiveBody(read_length); }); } I'm sure this bug will fall in the morning. I know well enough that I've stared at this too long for one day. But my confusion is augmented by knowing that the accept(2) system call returns a new file descriptor: int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); So my hypothesis this afternoon was briefly that asio's async_accept() must be doing the same thing and that I'm therefore calling read on the listening socket and not on the new connected socket. That doesn't quite make sense anyway, because I can see via netstat that no socket is connected (and I didn't run my utility to connect, and this is a quiescent vm constructed just for these tests). But this is bothering me now, because I've also spent a bunch of time reading in /usr/include/boost/asio/ and I don't find the call to the underlying system call accept(). My question is mostly on this last point: wtf, where is the connected fd represented in asio? -- Jeff Abrahamson +33 6 24 40 01 57 +44 7920 594 255 https://www.p27.eu/jeff/<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.p27.eu%2Fjeff%2F&data=02%7C01%7Cmatthew.gruenke%40jci.com%7C6ff6fe5241de41067cf108d66d11eaef%7Ca1f1e2147ded45b681a19e8ae3459641%7C0%7C0%7C636816321066716841&sdata=h2zRyXFLnhpNmTN9dceL%2FTciX%2F5km5bpn8l6Ue8ZUgU%3D&reserved=0> https://www.transport-nantes.com/<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.transport-nantes.com%2F&data=02%7C01%7Cmatthew.gruenke%40jci.com%7C6ff6fe5241de41067cf108d66d11eaef%7Ca1f1e2147ded45b681a19e8ae3459641%7C0%7C0%7C636816321066716841&sdata=BgNiAjn3tA%2FoC3G8pJVocnTiIbOxnmHaeHzob%2F2aYFM%3D&reserved=0> |