[asio] sending and receiving binary

Hello, all - After starting from scratch again, I've been able to climb into boost::asio and am beginning to get it to work. Please bear with me; I'm still a noob when it comes to reading C++ templates. I started by building the little asynchronous daytime server into my primary application, and used the asynch client to successfully talk to it. All well and good. Now, I've built my real message, which is mixed 7-bit ASCII and binary data (counts, checksums, etc.). In experimenting to make it work, I've started changing my code in the server and client to be more like the echo server. It appears to be accepting the message, but when it tries to respond the async_write() function throws an error: ERROR: 'system:0' has occurred. ... and I see 'connection reset by peer' on the client side. I don't THINK it's because I'm sending binary; this is more likely a glitch in my understanding of boost::asio. I'll back up and look at the daytime and echo examples again and try to see what I've messed up, but I thought I'd put this out there as I've been slogging in mud for a few hours now. :) // ---- server code ---- // server using boost::asio::ip::tcp; TCPConnection::TCPConnection(boost::asio::io_service& aIOService) : _socket(aIOService) { } boost::shared_ptr<TCPConnection> TCPConnection::Create(boost::asio::io_service& aIOService) { return boost::shared_ptr<TCPConnection>(new TCPConnection(aIOService)); } tcp::socket& TCPConnection::Socket() { return _socket; } void TCPConnection::CheckMessageAndRespond() { _message = make_my_daytime_string(); boost::asio::async_write( _socket, boost::asio::buffer(_message), boost::bind(&TCPConnection::HandleWrite, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void TCPConnection::HandleWrite( const boost::system::error_code& aError, std::size_t aNumBytes) { std::cerr << "ERROR: '" << aError << "' has occurred." << std::endl; } std::string TCPConnection::make_my_daytime_string() { std::time_t now = std::time(0); return std::ctime(&now); } static const int QUERYIPADDR = 2000; TCPServer::TCPServer(boost::asio::io_service& aIOService) : _acceptor(aIOService, tcp::endpoint(tcp::v4(), QUERYIPADDR)) { StartAccept(); } void TCPServer::StartAccept() { boost::shared_ptr<TCPConnection> newconnection = TCPConnection::Create(_acceptor.io_service()); _acceptor.async_accept( newconnection->Socket(), boost::bind(&TCPServer::HandleAccept, this, newconnection, boost::asio::placeholders::error)); std::cout << "Extender inquiry server ready for business!" << std::endl; } void TCPServer::HandleAccept( boost::shared_ptr<TCPConnection> aNewConnection, const boost::system::error_code& aError) { if (!aError) { aNewConnection->CheckMessageAndRespond(); StartAccept(); } } //---- main equiv (within another class) ---------------------- ExtenderServer::ExtenderServer(TVED::ITVExtenderDeviceHandler* aEDHandler) { try { boost::asio::io_service ioservice; TCPServer Server(ioservice); ioservice.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } } //-------- client (extracted code) ------------------------- string message; message.reserve(1024); ... size_t mlen = message.length(); const char* mptr = 0; mptr = message.data(); // Create new IO network client service boost::asio::io_service io_service; // Attach a Query Resolver to it tcp::resolver resolver(io_service); // We will talk to a Well Known Port (currently 2000) tcp::resolver::query query(tcp::v4(), argv[3], "2000"); tcp::resolver::iterator iterator = resolver.resolve(query); tcp::socket socket(io_service); socket.connect(*iterator); boost::system::error_code error; size_t lwrite = boost::asio::write(socket, boost::asio::buffer(mptr, mlen)); if (error) { throw boost::system::system_error(error); // Some error occurred. } cout << "Wrote " << lwrite << " bytes" << endl; char buf[1024]; size_t len; while (1) { char buf[1024]; len = socket.read_some(boost::asio::buffer(buf), error); if (error == boost::asio::error::eof) { cout << "eof" << endl; break; } else if (error) { throw boost::system::system_error(error); // Some other error. } } string response; stringstream sbuf (response, stringstream::in | stringstream::out | stringstream::binary); sbuf.write(buf, len); cout << endl << "Message string server returns: " << endl; print_message(&response); } catch (std::exception& e) { std::cerr << "ERR from faker: " << e.what() << std::endl; } // ---------------------------------run data ----------------------- // example data // as sent by client "faker" program Message string client sends: ASCII: I N T C :: :: :: / :: :: :: :: :: :: :: :: 0 0 : 1 3 : 2 0 : f 9 : 2 a : 8 9 | 1 9 2 . 1 6 8 . 0 . 1 0 | 3 0 0 0 F N :: H Binary: 49 4E 54 43 00 00 00 2F 00 00 00 00 00 00 00 00 30 30 3A 31 33 3A 32 30 3A 66 39 3A 32 61 3A 38 39 7C 31 39 32 2E 31 36 38 2E 30 2E 31 30 7C 33 30 30 30 46 4E 8D 48 Wrote 55 bytes ERR from faker: Connection reset by peer TIA for suggestions! :D -- Don Wilde

It appears to be accepting the message, but when it tries to respond the async_write() function throws an error:
ERROR: 'system:0' has occurred.
It means there's no error. Test error_code like this: if (aError) {...}.
... and I see 'connection reset by peer' on the client side.
Your HandleWrite doesn't initiate another i/o operation, doesn't create another handler bound to shared_from_this, so the TCPConnection instance gets destroyed along with its socket.

It appears to be accepting the message, but when it tries to respond the async_write() function throws an error:
ERROR: 'system:0' has occurred.
It means there's no error. Test error_code like this: if (aError) {...}.
Hmm...thought I was. :)
... and I see 'connection reset by peer' on the client side.
Your HandleWrite doesn't initiate another i/o operation, doesn't create another handler bound to shared_from_this, so the TCPConnection instance gets destroyed along with its socket.
Ah, the other version did, but this one doesn't. I misunderstood and thought HandleWrite was only bound to the error occurrence. I only want the connection to live through one send and one reply, but if I understand you correctly I have to beg it to stay alive long enough for the reply to go out? Okay, thanks for your patience, Igor! :D

Ah, the other version did, but this one doesn't. I misunderstood and thought HandleWrite was only bound to the error occurrence. I only want the connection to live through one send and one reply, but if I understand you correctly I have to beg it to stay alive long enough for the reply to go out?
If you don't need it anymore, you don't have to... I don't see where your server code receives anything, but anyway, if all you need is to ensure that the data being sent with async_write won't be discarded due to socket closing, I believe you can just set linger option: http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/reference/socket_ba...

Ah, the other version did, but this one doesn't. I misunderstood and thought HandleWrite was only bound to the error occurrence. I only want the connection to live through one send and one reply, but if I understand you correctly I have to beg it to stay alive long enough for the reply to go out?
If you don't need it anymore, you don't have to... I don't see where your server code receives anything, but anyway, if all you need is to ensure that the data being sent with async_write won't be discarded due to socket closing, I believe you can just set linger option: http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/reference/socket_ba...
I hadn't gotten that far yet. I still need to add code to grab the message and interpret it, then build the real reply. I don't want this port to be tied up for long because it is meant to allow handheld devices to request connections which will be fulfilled by other sockets on other ports. Once this socket receives a request, I merely want to ack it and close the connection. The TV will then build permanent TCP and UDP connections with the device using the info from the initial request. The 'daytime' code is just a placeholder. Thanks for the tips! I have no doubt it's all in there, I just need to learn to use it. :D
participants (2)
-
Igor R
-
Wilde, Donald S