Boost :: asio UDP使用临时端口进行广播

时间:2013-08-23 08:03:41

标签: windows sockets udp boost-asio

我在boost :: asio下遇到udp广播事务有问题,与以下代码片段有关。由于我试图在这种情况下进行广播,所以deviceIP =" 255.255.255.255"。 devicePort是我的设备的指定管理端口。我想使用一个短暂的本地端口,所以我希望在连接之后根本不需要socket.bind(),并且代码通过设置localPort = 0来支持单播。

boost::asio::ip::address_v4 targetIP = boost::asio::ip::address_v4::from_string(deviceIP);
m_targetEndPoint = boost::asio::ip::udp::endpoint(targetIP, devicePort);

m_ioServicePtr = boost::shared_ptr<boost::asio::io_service>(new boost::asio::io_service);
m_socketPtr = boost::shared_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(*m_ioServicePtr));
m_socketPtr->open(m_targetEndPoint.protocol());

m_socketPtr->set_option(boost::asio::socket_base::broadcast(true));

// If no local port is specified, default parameter is 0
// If local port is specified, bind to that port.
if(localPort != 0)
{
  boost::asio::ip::udp::endpoint localEndpoint(boost::asio::ip::address_v4::any(), localPort);
  m_socketPtr->bind(localEndpoint);
}

if(m_forceConnect)
  m_socketPtr->connect(m_targetEndPoint);

this->AsyncReceive(); // Register Asynch Recieve callback and buffer
m_socketThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&MyNetworkBase::RunSocketThread, this))); // Start thread running io_service process

无论我在以下设置方面做了什么,传输工作正常,我可以使用Wireshark查看从设备返回的响应数据包。这些响应数据包也是广播,因为设备可能与搜索它的电脑位于不同的子网上。

这个问题在我看来非常奇怪,但如下:

  1. 如果我指定本地端口并设置m_forceConnect = false,则一切正常,我的接收回调会正确触发。
  2. 如果我在构造函数中设置了m_forceConnect = true,但传入的本地端口为0,则传输工作正常,但我的接收回调永远不会触发。我认为这是因为&#39;目标&#39; (m_targetEndpoint)为255.255.255.255,由于设备具有真实IP,因此过滤掉了响应数据包。
  3. 我真正想要的)如果m_forceConnect = false(并且使用send_to调用传输数据),并且本地端口= 0,因此采用临时端口,我的RX回调会立即触发错误代码10022,我认为这是一个&#34;无效的参数&#34;套接字错误。
  4. 有人可以建议我为什么不能以这种方式使用连接(没有明确绑定和未明确连接)?在这种情况下,我显然不想使用socket.connect(),因为我想回应我收到的任何内容。我也不想使用预定义的端口,因为我希望用户能够构造此对象的多个副本而不会发生端口冲突。

    正如有些人可能已经注意到的,这样做的总体目标是使用相同的网络接口基类来处理单播和广播情况。显然,对于单播版本,我非常高兴m_socket-&gt; connect()因为我知道设备的IP,并且我收到响应,因为他们来自连接的IP地址,因此我设置了m_forceConnect =是的,一切正常。

    由于我的所有传输都使用send_to,我也尝试过socket.connect(端点(ip :: addressv4 :: any(),devicePort),但我得到了一个&#39;请求的地址在其中无效当我尝试它时,语境异常。

    我尝试过非常严重的黑客行为:

    boost::asio::ip::udp::endpoint localEndpoint(boost::asio::ip::address_v4::any(), m_socketPtr->local_endpoint().port());
    m_socketPtr->bind(localEndpoint);
    

    我在哪里提取初始临时端口号并尝试绑定到它,但有趣的是,当我尝试绑定时会抛出一个无效的参数异常。

1 个答案:

答案 0 :(得分:4)

好的,我找到了解决这个问题的方法。在linux下没有必要,但是在Windows下我发现如果你既没有绑定也没有连接,你必须在调用asynch_recieve_from()之前传输某些东西,其调用包含在我的内容中this-&gt; asynch_receive()方法。

我的解决方案是,在windows下进行asynch_receive调用之前立即进行空字符串的虚拟传输,因此修改后的代码变为:

m_socketPtr->set_option(boost::asio::socket_base::broadcast(true));

// If no local port is specified, default parameter is 0
// If local port is specified, bind to that port.
if(localPort != 0)
{
  boost::asio::ip::udp::endpoint localEndpoint(boost::asio::ip::address_v4::any(), localPort);
  m_socketPtr->bind(localEndpoint);
}

if(m_forceConnect)
  m_socketPtr->connect(m_targetEndPoint);

// A dummy TX is required for the socket to acquire the local port properly under windoze
// Transmitting an empty string works fine for this, but the TX must take place BEFORE the first call to Asynch_receive_from(...)
#ifdef WIN32
m_socketPtr->send_to(boost::asio::buffer("", 0), m_targetEndPoint);
#endif

this->AsyncReceive(); // Register Asynch Recieve callback and buffer
m_socketThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&MyNetworkBase::RunSocketThread, this)));

这在我的书中有点黑客,但它比实现所有要求更好,直到第一次传输之后将调用推迟到异步接收。