基于UDP的设备查找

需求描述
设备为通讯管理机,在一个局域网内会有多个这样的设备,然后通过上位机,需要能查询到局域网内通讯管理机的IP地址。

思路
开发语言上位机、下位机都采用了Qt,然后准备用Udp来实现,折腾了一下午,目前测试效果还不错,基本思路如下:

  • 管理机加入到组播,监听组播报文,比如组播地址为“239.255.43.21”;
  • 上位机不加入到组播,需要查询的时候,直接给组播地址发送请求设备IP报文;
  • 管理机从组播网络接收到指令以后,直接给上位机地址(也就是报文发送地址)回复包含自己的IP地址

注意事项

  • UDP报文在有多个实体网卡或者虚拟网卡的系统上,一定要注意指定对应的网卡,否则会出现发不出来或者接收不到的情况。
  • 上位机未加入到组播,所以指定网卡,通过网卡上的IP地址即可;
  • 下位机加入到了组播,所以不能指定IP,只能在加入组播的时候,指定网卡;
  • 具体实现,请见代码示例。

代码实现

上位机实现:

MainWindow::MainWindow()
{
        m_udpSocket = new QUdpSocket(this);
        connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(OnReadPendingDatagrams()));
        m_udpSocket->bind(QHostAddress(ip), 45454);
}

void MainWindow::OnReadPendingDatagrams()
{
    while (m_udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(m_udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        m_udpSocket->readDatagram(datagram.data(), datagram.size(),
                                &sender, &senderPort);

        QDataStream in(&datagram, QIODevice::ReadOnly);
        in.setByteOrder(QDataStream::BigEndian);
        quint16 tag,cmd;
        in >> tag >> cmd;
        if(tag == 0x7878 && cmd == 2)
        {
            QString ip,mas;
            in >> ip >> mas;
            ui->textEdit->append(tr("找到装置:%1  %2").arg(ip).arg(mas));
        }
    }
}

void MainWindow::SearchDevice()
{
    quint16 tag,cmd;
    tag = 0x7878;
    cmd = 1;
    QByteArray sBuffer;
    QDataStream out(&sBuffer, QIODevice::WriteOnly);
    out.setByteOrder(QDataStream::BigEndian);
    cmd = 1;
    out << tag << cmd;
    ui->textEdit->append(tr("查找装置中…… %1").arg(m_udpSocket->writeDatagram(sBuffer, QHostAddress("239.255.43.21"), 45455)));
}

下位机实现:

MainWindow:MainWindow()
{
    m_udpSocket = new QUdpSocket(this);
    m_groupAddress = QHostAddress("239.255.43.21");
    m_udpSocket->bind(QHostAddress::AnyIPv4, 45455, QUdpSocket::DontShareAddress);
    QList<QNetworkInterface> interfaceList = QNetworkInterface::allInterfaces();
    QNetworkInterface bindInterfac;
    foreach (QNetworkInterface interfac, interfaceList)
    {
        qDebug() << "network:" << interfac.humanReadableName();
        if(interfac.humanReadableName() == "eth0")
        {
            bindInterfac = interfac;
        }
    }
    qDebug() << "join group" << m_udpSocket->joinMulticastGroup(m_groupAddress, bindInterfac);
    connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(OnReadPendingDatagrams()));
}

void MainWindow::OnReadPendingDatagrams()
{
    while (m_udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(m_udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        m_udpSocket->readDatagram(datagram.data(), datagram.size(),
                                &sender, &senderPort);

        QDataStream in(&datagram, QIODevice::ReadOnly);
        in.setByteOrder(QDataStream::BigEndian);
        quint16 tag,cmd;
        in >> tag >> cmd;
        if(tag == 0x7878 && cmd == 1)
        {
            QByteArray sBuffer;
            QDataStream out(&sBuffer, QIODevice::WriteOnly);
            out.setByteOrder(QDataStream::BigEndian);
            cmd = 2;
            out << tag << cmd
                << CXMLHelper::ConfigValue("manager_ip").toString()
                << CXMLHelper::ConfigValue("manager_mask").toString();
            qDebug() << "send:" << m_udpSocket->writeDatagram(sBuffer, sender, 45454);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值