Unix上的Boost UDP套接字问题 - 绑定:地址已在使用中 [英] Boost UDP socket issue on unix - bind: address already in use

查看:485
本文介绍了Unix上的Boost UDP套接字问题 - 绑定:地址已在使用中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我知道在同一个主题上有几个其他线程,但我找不到任何可以帮助我的东西,所以我会尽量对我的情况非常具体。



我设置了一个简单的UDP客户端/ UDP服务器对,负责在几个并行模拟之间发送数据。也就是说,模拟器的每个实例都在单独的线程中运行,并在UDP套接字上发送数据。在主线程中,服务器正在运行,并在模拟之间路由消息。



服务器代码的重要部分(对于此问题)如下所示:

  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(){

//将SO_REUSABLE设置为true
boost :: asio :: socket_base :: reuse_address选项(true);
this-> m_socket.set_option(option);

//指定接收到消息时会发生什么(它应该调用handle_receive函数)
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));

};

这在我的Windows工作站上正常工作。



<事情是;我想能够在一个linux集群上运行这,这就是为什么我编译它,并试图在集群节点上运行它。代码编译时没有困难,但是当我尝试运行它我得到错误

  bind:地址已在使用

我使用高于1024的端口号,并且已经验证它未被另一个程序使用。正如上面所看到的,我还设置了 reuse_address 选项,所以我真的不知道还有什么错误。

解决方案

SO_REUSEADDR 在将套接字绑定到通配符地址之前需要设置该选项:

  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();
}

在原始代码中,构造函数采用 endpoint 构造,在一行中打开和绑定套接字 - 它简洁但不是很灵活。这里我们在构造函数调用中构造和打开套接字,然后在设置选项后绑定它。



另外, code> m_endpoint 如果你只是要使用它作为 async_receive_from 的out参数。


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.

解决方案

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.

这篇关于Unix上的Boost UDP套接字问题 - 绑定:地址已在使用中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆