QT UDP Socket数据接收与解析

主题概要
QTUDP Socket
编辑时间
新建20180331
序号参考资料
1https://doc.qt.io/qt-5/qudpsocket.html

做直升机航电系统仿真,类似GPS导航接收机的按钮很多,显示的仪表也很多。
这里写图片描述
按钮的状态是通过底层程序通过UDP发送给控制层的,层次逻辑如下图所示:
这里写图片描述

现在要实现的功能是用QT自带的QUdpSocket,实现端口的监听,收到数据后,解析并把数据派发到具体的模块。

现在收发的数据结构(类)是:InstrumentBtn,基础设施的按钮信息。这里忽略具体的内容,只需知道字段是全值类型,不需要实现深层拷贝, 复用下面的代码时,只需要按需要替换为自己的数据结构(类)即可。

类定义

定义一个InstrumentBtnWorker,表示一个解析基础设施按钮的工人。

#ifndef ASM_INSTRUMENT_BTN_WORKER_H
#define ASM_INSTRUMENT_BTN_WORKER_H

#include <QUdpSocket>
#include <QReadWriteLock>
#include "net_fdm.h"

class InstrumentBtnWorker:public QObject
{
    Q_OBJECT
public:
    static InstrumentBtnWorker * instance();
    void destory();
signals:
    void signalBtnValueChanged(InstrumentBtn btnValue);

private slots:
    void readPendingDatagrams();

private:
    InstrumentBtnWorker();
    virtual ~InstrumentBtnWorker();

    void initSocket();
    void processDatagram(char * datagram,int len);
    void dispatchBtnValue(InstrumentBtn btnValue);

    static InstrumentBtnWorker * m_instance;
    QUdpSocket udpSocket;
};



#endif // ASM_INSTRUMENT_BTN_WORKER_H

net_fdm.h头文件里面定义了InstrumentBtn结构。
该类采用单例模式。

类实现

初始化socket:

void InstrumentBtnWorker::initSocket()
{
    udpSocket.bind(GPSGLConfige::INSTRUMENT_BTN_UDP_PORT);
    connect(&udpSocket, SIGNAL(readyRead()),this, SLOT(readPendingDatagrams()));
}

绑定端口号,连接readyRead信号与处理槽。

缓存数据,并把数据传递给processDatagram处理。

void InstrumentBtnWorker::readPendingDatagrams()
{
    QByteArray datagram;
    while (udpSocket.hasPendingDatagrams())
    {
        int sizeLen=udpSocket.pendingDatagramSize();
        datagram.resize(sizeLen);
        udpSocket.readDatagram(datagram.data(),datagram.size());
        processDatagram(datagram.data(),sizeLen);
    }
}

数据处理:

void InstrumentBtnWorker::processDatagram(char * datagram,int len)
{
    InstrumentBtn btnValue;
    if(len>0)
    {
        btn_input(datagram,&btnValue);
        dispatchBtnValue(btnValue);
    }
}

其中的btn_input直接用memcpy强制转换数据:

void btn_input(char* buf,InstrumentBtn* btn)
{
    if(buf==NULL || btn==NULL)
    {
        return;
    }


    memset(btn,0,sizeof(InstrumentBtn));
    memcpy(btn,buf,sizeof(InstrumentBtn));
}

这种偷懒的做法不知道对不对,比较担心代码的移植性,结构没有1字节对齐,也没有对传输对象序列化与反序列化。但现在来看,还是能正常工作。

dispatchBtnValue,派发数据,实际上只是发送自定义的signalBtnValueChanged信号,利用QT自带的信号-槽机制实现数据传输。

/*
Note:需确保InstrumentBtn全为值类型,如果有引用类型,需实现深层拷贝
*/
void InstrumentBtnWorker::dispatchBtnValue(InstrumentBtn btnValue)
{
    emit signalBtnValueChanged(btnValue);
}

私有构造函数、析构函数:

InstrumentBtnWorker * InstrumentBtnWorker::m_instance=NULL;
InstrumentBtnWorker * InstrumentBtnWorker::instance()
{
    QReadWriteLock lock;
    if(m_instance==NULL)
    {
        lock.lockForWrite();
        if(m_instance==NULL)
        {
            m_instance=new InstrumentBtnWorker();
        }
        lock.unlock();
    }

    return m_instance;
}

InstrumentBtnWorker::InstrumentBtnWorker()
{
    initSocket();
}

InstrumentBtnWorker::~InstrumentBtnWorker()
{
}

类使用

在需要接收数据的地方,实现自己的接收槽函数,并连接到InstrumentBtnWorker的signalBtnValueChanged信号:

InstrumentBtnWorker * btnWorker=InstrumentBtnWorker::instance();

    btnWorker->connect(btnWorker,SIGNAL(signalBtnValueChanged(InstrumentBtn)),this,SLOT(slotOnBtnChanged(InstrumentBtn)));

如果没有信号和槽机制,C++中又没有C#中的委托机制,还需要自己去实现观察者模式,维护一个观察者列表。

  • 10
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ 和 Qt 都提供了对 UDP socket 的支持。下面是一个简单的示例,展示了如何使用 Qt 中的 QUdpSocket 类发送和接收数据。 发送端代码: ```cpp #include <QtNetwork> int main() { QUdpSocket udpSocket; QByteArray data = "Hello, world!"; udpSocket.writeDatagram(data, QHostAddress::Broadcast, 12345); return 0; } ``` 接收端代码: ```cpp #include <QtNetwork> int main() { QUdpSocket udpSocket; udpSocket.bind(QHostAddress::Any, 12345); while (udpSocket.waitForReadyRead()) { QByteArray datagram; datagram.resize(udpSocket.pendingDatagramSize()); udpSocket.readDatagram(datagram.data(), datagram.size()); qDebug() << "Received: " << datagram; } return 0; } ``` 这个例子中,发送端将一个字符串 "Hello, world!" 发送到本地局域网内的所有设备。接收端监听端口 12345,等待数据到来。当有数据到来时,接收端会输出收到的数据。注意,在这个例子中,发送端和接收端都在同一台机器上,因此可以使用广播地址发送数据。 要在 Qt 中使用 UDP socket,必须包含头文件 `QUdpSocket`,并创建一个 `QUdpSocket` 对象。发送数据时,使用 `writeDatagram()` 方法;接收数据时,使用 `readDatagram()` 方法。在接收数据之前,必须先调用 `bind()` 方法,指定要监听的端口和 IP 地址。 需要注意的是,UDP 是无连接的,因此发送数据时不需要建立连接,只需要指定目标地址和端口号即可。但是,这也意味着 UDP数据传输是不可靠的,因为数据包可能会在传输过程中丢失或乱序。因此,在使用 UDP 时,需要考虑数据丢失和乱序的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值