我的 Qt 应用程序使用多播QUdpSocket
并且需要半双工操作(它模拟单工无线电台之间的无线电传输)。这意味着一个应用程序实例不能接收它发送的数据报。但它还必须支持在同一台机器上工作多个实例(用户明确选择环回接口)。而且,当然,它应该是可移植的(最坏的情况是 Windows 和 Linux)。
我知道IP_MULTICAST_LOOP
套接字选项和类似的问题:
模拟环回接口上的多播,环回设备上的多播,有没有办法在同一个盒子上测试多播 IP?,如何通过 localhost 使用多播来限制流量,可以将来自不同进程的数据多播到同一主机和端口吗?.
讨论几乎可以回答我的问题,但仍不清楚(主要是因为在我看来,不同平台上的行为有所不同)。
那么我应该如何设置套接字?如果无法通过简单的连接配置来实现它,那么也许使用带有 ReadOnly/WriteOnly 的 connectToHost() 将有助于保证?
更新:
这是我的研究结果,它似乎可以工作,但我不相信它可以在平台和网络配置的任何其他组合上工作,除了我的电脑有:
void initNetwork() {
//...
/* It will be needed to filter out own loopbacked datagrams */
local_addresses = QNetworkInterface::allAddresses();
/* Interface, selected by user */
QNetworkInterface multicast_netif = <user selected>;
Q_ASSERT(multicast_netif.isValid());
/* Yes, I already accept the fact, that I need two separate sockets (there are more chances to make it work than when using bidirectional one) */
udpSocketIn = new QUdpSocket(this);
udpSocketOut = new QUdpSocket(this);
/* It's important to bind to Any. No other combinations work (including LocalHost (in case if user selected loopback interface), MULTICAST_ADDR) */
result = udpSocketIn->bind(QHostAddress::Any, MULTICAST_PORT, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
Q_ASSERT(result);
/* It required to only make application know real(!) udpSocketOut->localPort() in order to be able filter own datagrams */
result = udpSocketOut->bind();
Q_ASSERT(result);
/* One of rare things, I'm sure is correct and must be done */
result = udpSocketIn->joinMulticastGroup(QHostAddress(MULTICAST_ADDR), multicast_netif);
Q_ASSERT(result);
/* It doesn't matter, but it will fail if socket not binded */
//result = udpSocketOut->joinMulticastGroup(QHostAddress(MULTICAST_ADDR), multicast_netif);
//Q_ASSERT(result);
/* No, you can't ! If socket binded previously and loopback interface selected, datagrams will not be transfered. I don't know why. And this is major thing, which makes me think, that this configuration isn't reliable, because stupid windows will select default interface for outgoing datagrams ! */
//udpSocketOut->setMulticastInterface(multicast_netif);
/* It doesn't matter, because it set by default. */
//udpSocketIn->setSocketOption(QAbstractSocket::MulticastLoopbackOption, QVariant(1));
//udpSocketOut->setSocketOption(QAbstractSocket::MulticastLoopbackOption, QVariant(1));
//...
}
void sendDatagram() {
//...
/* It almost always return ok, regardless of datagram being sent actually or not.
One exception is when I turn off real network interface to which it was binded by udpSocketOut->bind() call (it selected by OS, although user selected loopback interface !)
*/
result = udpSocketOut->writeDatagram(datagram, QHostAddress((MULTICAST_ADDR), MULTICAST_PORT);
Q_ASSERT(result == datagram.size());
//...
}
void readPendingDatagrams() {
//...
udpSocketIn->readDatagram(datagram, &senderHost, &senderPort);
/* Thanks to udpSocketOut->bind() we are able to filter out own packets sent from udpSocketOut */
if ((local_addresses.contains(senderHost)) && (senderPort == udpSocketOut->localPort())) {
// Ignore loopbacked datagram
return;
}
//...
抱歉格式错误,这是因为我无法赢得烦人的问题