6

First of all, I know there are several other threads on the same theme, but I was unable to find anything in those that could help me so I'll try to be very specific with my situation.

I have set up a simple UDP Client / UDP Server pair that is responsible to send data between several parallel simulations. That is, every instance of the simulator is running in a separate thread and send data on a UDP socket. In the master thread the server is running and routes the messages between the simulations.

The (for this problem) important parts of the server code looks like this:

UDPServer::UDPServer(boost::asio::io_service &m_io_service) :
   m_socket(m_io_service, udp::endpoint(udp::v4(), PORT_NUMBER)),
   m_endpoint(boost::asio::ip::address::from_string("127.0.0.1"), PORT_NUMBER)
{
   this->start_receive();
};

void UDPServer::start_receive() {

   // Set SO_REUSABLE to true
   boost::asio::socket_base::reuse_address option(true);
   this->m_socket.set_option(option);

   // Specify what happens when a message is received (it should call the handle_receive function)
   this->m_socket.async_receive_from(   boost::asio::buffer(this->recv_buffer),
                                        this->m_endpoint,
                                        boost::bind(&UDPServer::handle_receive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

};

This works fine on my windows workstation.

The thing is; I want to be able to run this on a linux cluster, which is why I compiled it and tried to run it on a cluster node. The code compiled without a hitch, but when I try to run it I get the error

bind: address already in use

I use a port number above 1024, and have verified that it is not in use by another program. And as is seen above, I also set the reuse_address option, so I really don't know what else could be wrong.

Fabian Jonsson
  • 131
  • 1
  • 9

2 Answers2

4

To portably use SO_REUSEADDR you need to set the option before binding the socket to the wildcard address:

UDPServer::UDPServer(boost::asio::io_service &m_io_service) :
   m_socket(m_io_service, udp::v4()),
   m_endpoint()
{
   boost::asio::socket_base::reuse_address option(true);
   this->m_socket.set_option(option);
   this->m_socket.bind(udp::endpoint(udp::v4(), PORT_NUMBER));
   this->start_receive();
}

In your original code, the constructor that takes an endpoint constructs, opens and binds the socket in a single line - it's concise but not very flexible. Here we're constructing and opening the socket in the constructor call, and then binding it later after we set the option.

As an aside, there's not much point initialising m_endpoint if you're just going to use it as the out argument of async_receive_from anyway.

Community
  • 1
  • 1
ecatmur
  • 137,771
  • 23
  • 263
  • 343
  • 1
    Thanks, I tried your modifications but get `set_option: Bad file descriptor` error. Any ideas? – Fabian Jonsson Sep 10 '14 at 07:18
  • Think I've solved it. I added a `this->m_socket.open(udp::v4());` before the `set_option()`. Now I get no errors. Does that make sense? – Fabian Jonsson Sep 10 '14 at 07:25
  • @FabianJonsson yes; your original code creates, opens and binds the socket in a single call (the `udp::socket` constructor). I'll expand my answer. – ecatmur Sep 10 '14 at 08:43
0

Try running the following command on Linux to see if the port is already being used by another program.

netstat -antup | grep 1024

If you are getting "address already in use" then it is definitely being used by some other program. If the above command yields some result, then kill the process id that is reported in the command. If this does not work, try changing the port number to some other arbitrary port and check if the problem persists.

chandra.v
  • 407
  • 4
  • 9
  • I've already verified that the port is not used. I've also tried with many different port numbers so I'm confident that's not the issue. – Fabian Jonsson Sep 10 '14 at 07:17