Qt 发UDP广播 服务端及客户端

355 阅读1分钟
  • Qt += network

数据结构

  • data_geo.h
    #pragma pack(1)
    struct DataGeoLines
    {
        DataGeoLine data[4];
        uint32_t num_lines_valid;
            uint64_t timestamp_ms;		    //毫秒时间戳
            EnumLinesPattern type_pattern;  //导线的类型
    };
    #pragma pack()
    
  • udp_data_wrap.h
    #pragma once  
    
    // 内存对齐
    #pragma pack(1)
    template<typename T>
    struct UDP_DATA_WRAP
    {
        UDP_DATA_WRAP():real_data_size(sizeof(T)){}
        uint16_t header{0xffee};
        uint64_t real_data_size{0};
        T real_data;
    };
    #pragma pack()
    

服务端

  • udpserver.hpp
    #pragma once
    #include <QUdpSocket>
    #include <stdint.h>
    
    class UDPServer
    {
    public:    
        bool init(uint64_t port_in){
            port = port_in;
            p_udpSocket = new QUdpSocket();
            if(nullptr == p_udpSocket) return false;
            else return true;}
        uint64_t send(char* p_data, uint64_t len){
            return p_udpSocket->writeDatagram(p_data, len, QHostAddress::Broadcast, port);
        }
    private:
        uint64_t port;
        QUdpSocket* p_udpSocket{nullptr};
    };   
    
  • 使用
    // send it, pass udp
    static UDPServer udp_server;
    static std::once_flag once_flag;
    std::call_once(once_flag, [&](){if(false == udp_server.init(9999)) printf("udp socket init failed \n");});
    uint64_t send_size =  udp_server.send((char*)&udp_data, sizeof(UDP_DATA_WRAP<DataGeoLines>));
    printf("send_size: %d \n", send_size);
    

客户端

  • udp_client.h
    #pragma once
    #include <QUdpSocket>
    #include <QObject>
    class UDPClient : public QObject
    {
        Q_OBJECT
    public:
        void init(uint16_t port_in);
        void readPendingDatagrams();    
    
        QUdpSocket* p_qudp_socket{nullptr};
    private:
        uint8_t p_buf[1024];
        std::string ip{"192.168.0.255"};
        uint16_t port{9999};
    };
    
  • udp_client.cpp
    #include "udp_client.h"
    #include <QNetworkDatagram>
    #include <QHostAddress>
    #include "data_geo.h"
    #include <iostream>
    #include <thread>
    
    void UDPClient::init(uint16_t port_in)
    {
        port = port_in;
        p_qudp_socket = new QUdpSocket(this);
        p_qudp_socket->bind(QHostAddress::Broadcast, port);
        connect(p_qudp_socket, &QUdpSocket::readyRead, this, &UDPClient::readPendingDatagrams);
    }
    
    void UDPClient::readPendingDatagrams()
    {
        while (p_qudp_socket->hasPendingDatagrams()) {
            int64_t len = p_qudp_socket->readDatagram((char*)p_buf, sizeof(p_buf), nullptr, &port);
            if(-1 == len)   continue;
            std::cout << "recive len: " << len << std::endl;
            uint16_t* p_header = (uint16_t*)&p_buf;
            if(*p_header == 0xffee)
            {
                DataGeoLines* p_data_geo_line =  (DataGeoLines*)&p_buf[10];
                printf("DataGeoLine num: %d \n", p_data_geo_line->num_lines_valid);
                printf("p_data_geo_line->data->height: %.2f \n", p_data_geo_line->data->height);
                printf("p_data_geo_line->data->stagger: %.2f \n", p_data_geo_line->data->stagger);
            }
        }
    }
    
  • 使用
    #include <QCoreApplication>
    #include "udp_client.h"
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        UDPClient udp_client;
        const uint16_t port = 9999;
        udp_client.init(port);
        return a.exec();
    }