Boost :: asio UDP广播与临时端口

我遇到了与boost :: asio下的udp广播事务有关的问题,与下面的代码片断有关。 由于我试图在这种情况下广播,所以deviceIP =“255.255.255.255”。 devicePort是我的设备的指定pipe理端口。 我想使用一个短暂的本地端口,所以我宁愿在连接之后不要必须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,一切正常,我的接收callback触发适当。
  2. 如果我在构造函数中设置m_forceConnect = true,但通过本地端口0,传输工作正常,但我的接收callback不会触发。 我会假设这是因为“目标”(m_targetEndpoint)是255.255.255.255,由于设备有一个真实的IP,响应数据包被过滤掉。
  3. 我真正想要的 )如果m_forceConnect = false(并使用send_to调用传输数据),并且本地端口= 0,因此采取一个短暂的端口,我的RXcallback立即引发错误代码10022,我相信是一个“无效的参数“套接字错误。

任何人都可以提出为什么我不能以这种方式使用连接(没有明确的约束和没有明确的连接)? 我明显不想在这种情况下使用socket.connect(),因为我想响应我收到的任何东西。 我也不想使用预定义的端口,因为我希望用户能够构造这个对象的多个副本而没有端口冲突。

正如有些人可能已经注意到的,其总体目标是使用相同的networking接口基类来处理单播和广播情况。 很显然,对于单播版本,我可以非常愉快地m_socket-> connect(),因为我知道设备的IP,并且因为它们来自连接的IP地址,所以我接收到响应,因此我设置了m_forceConnect = true, 。

由于我所有的传输使用send_to,我也尝试socket.connect(端点(ip :: addressv4 ::任何(),devicePort),但我得到一个'请求的地址是无效的在其上下文'exception,当我尝试它。

我已经尝试了一个非常严重的黑客攻击:

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

在那里我提取了初始的短暂端口号,并试图绑定到它,但有趣的是,当我尝试绑定时抛出一个无效参数exception。

好的,我找到了解决这个问题的方法。 在linux下不需要,但是在windows下,我发现如果你既没有绑定也没有连接,你必须在你调用asynch_recieve_from()之前发送了一些东西 ,这个调用被包含在我的this-> asynch_receive()方法中。

我的解决方案,在窗口之前进行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))); 

这在我的书中有些瑕疵,但比起实施所有的要求来推迟到异步接收的呼叫,直到第一次传输之后要好得多。