Reputation: 165
I've got two test programs (A & B)that are nearly identical, that use the same boost asio UDP async code.
Here is the receive call:
_mSocket.async_receive_from(
boost::asio::buffer(_mRecvBuffer), _mReceiveEndpoint,
boost::bind(&UdpConnection::handle_receive, this,_mReceiveEndpoint,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
// _mReceiveEndpoint is known and good. the buffer is good too.
// here's the handler
void handle_receive(const udp::endpoint recvFromEP, const boost::system::error_code& error,std::size_t bytesRecv/*bytes_transferred*/)
{
boost::shared_ptr<std::string> message(new std::string(_mRecvBuffer.c_array(),bytesRecv));
if (!error)
{
doSomeThingGood();
}
else {
cerr << "UDP Recv error : " << error << endl;
}
}
So here's what happens, all on localhost.
If I start program 'A' first, then program 'B', 'A' gives a UDP Recv error : server:10061. Program 'A' continues to send just fine and 'B' receives just fine.
You can swap 'A' and 'B' in the above sentence and it is still true.
IF I attempt a reset of the bad read condition by calling mSocket.async_receive_from again, I get error 10054.
I've looked these errors up on the web..... not very helpful.
Anybody have any ideas as to what these mean, and how I can recover inside the program if this condition occurs? Is there a way to reset the socket?
Sanity check.... can both programs operate on loopback with only two ports? A send = 20000, A receive = 20001 B send = 20001, B receive = 20000
TL;DR It appears as though if I try to listen before I'm sending, I get an error & I can't recover from it. If I listen after sending, I'm fine.
-- EDIT - It appears that McAfee host intrusion prevention is doing something nasty to me.... If I debug in VS2010, I get stuck in their DLL.
Thanks
Upvotes: 0
Views: 1580
Reputation: 813
Several sources explain that you should use SO_REUSEADDR on windows. But none mention that it is possible to receive UDP message with and without binding the socket. The code below binds the socket to a local listen_endpoint, that is essential, because without that you can and will still receive your UDP messages, but by default your will have exclusive ownership of the port.
However if you set reuse_address(true) on the socket (or on the acceptor when using TCP), and bind the socket afterwards, it will enable multiple applications, or multiple instances of your own application to do it again, and everyone will receive all messages.
// Create the socket so that multiple may be bound to the same address.
boost::asio::ip::udp::endpoint listen_endpoint(
listen_address, multicast_port);
// == important part ==
socket_.open(listen_endpoint.protocol());
socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true));
socket_.bind(listen_endpoint);
// == important part ==
boost::array<char, 2000> recvBuffer;
socket_.async_receive_from(boost::asio::buffer(recvBuffer), m_remote_endpoint,
boost::bind(&SocketReader::ReceiveUDPMessage, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)
source: http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/multicast/receiver.cpp
Upvotes: 0
Reputation: 165
In my receive handler, I wasn't calling _mSocket.async_receive_from() again.... I just printed the error and exited.
Silly mistake, just posting here in case it helps anyone else.
Also for a similar problem with a different resolution: _mSocket.set_option(boost::asio::socket_base::reuse_address(true));
helps if you have multiple listeners.
Upvotes: 2