QT上位機:局域網特定設備ip查詢和顯示


運行環境:win10

QT版本:5.11.3


最近在研究QT如何將局域網的設備IP顯示在列表中,然後通過雙擊打開,調用web瀏覽器訪問一個固定的網址。因爲這裏是特定的設備,並且是局域網中的,那麼我們可以通過設計一個協議來處理這個問題。什麼協議最適合這樣的場景呢?熟悉網絡協議的童鞋一直知道UDP有個廣播地址。當廣播一條消息時,處於統一局域網中的UDP的客戶端或者是服務器都能收到這條消息。知道大概的方向後,下面就是開始擼代碼了:

首先,先打開QT Creator,新建一個工程,暫且名字爲qt_iot_dev_find。建立好工程後,我們打開工程中mainwindows.ui,進行頁面佈局。這裏的話,涉及的業務比較簡單,就三個控件,頁面佈局如下:

因爲這個工程要涉及到網絡編程,所以我們要打開工程文件qt_iot_dev_find.pro,在第8行添加一行代碼:

QT += network

添加完了之後,我們打開mainwindow.h頭文件,修改頭文件如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <QUdpSocket>//添加頭文件

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void list_init();//列表初始化
    void udp_server_init();//upd服務器初始化
    void iot_dev_ip_item_add(QString ip,QString data);//將獲取到的ip和數據,加入到列表中
    QUdpSocket *udp_server;
private:
    Ui::MainWindow *ui;

//添加槽函數
private slots:
    void udp_receive_data_handler();//自己添加的slot,在收到upd消息後,會自動調用該函數

    void on_search_dev_pushButton_clicked();//該函數是自動添加的,按鍵連接的槽函數
};

#endif // MAINWINDOW_H

然後打開mainwindow.cpp,修改cpp文件如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QListWidgetItem> //添加頭文件,我們是一個item一個item的插入


#define UDP_SERVER_PORT    12345
#define VALID_DATA         "ping_request" //有效數據.當前udp服務器認的有效數據,客戶端只需要發這個,就可以顯示在列表中
#define MAX_NUM             5             //顯示最大爲5,這個隨意更改

static unsigned char g_connect_count = 0;//連接數統計
static QString ip_all[MAX_NUM][32];//用來緩存連接的ip

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    list_init();
    udp_server_init();
}

MainWindow::~MainWindow()
{
    delete ui;
}

//列表初始化
void MainWindow::list_init()
{
    //初始化列表頭,暫定爲ip_addr和data
    QListWidgetItem *list_head = new QListWidgetItem("      ip_addr     \t     data",ui->dev_infor_listWidget);
    ui->dev_infor_listWidget->insertItem(1,list_head);
    //
}

//Upd服務器初始化
void MainWindow::udp_server_init()
{
    //創建一個udp server對象
    udp_server = new QUdpSocket(this);
    //綁定端口號爲12345
    udp_server->bind(UDP_SERVER_PORT,QUdpSocket::ShareAddress);
    //連接到slots,有客戶端的消息到來時,會自動調用udp_receive_data_handler
    connect(udp_server,SIGNAL(readyRead()),this,SLOT(udp_receive_data_handler()));

}

void MainWindow::udp_receive_data_handler()
{
    QHostAddress udp_client_address;//聲明一個QHostAddress對象
    unsigned short int udp_client_port = 0;//客戶端端口號
    QByteArray udp_datagram;//upd client 發來的數據,裏面包含內容和大小

    while( udp_server->hasPendingDatagrams() )
    {
        udp_datagram.resize( udp_server->pendingDatagramSize());

        udp_server->readDatagram(udp_datagram.data(),udp_datagram.size(), &udp_client_address, &udp_client_port);

        //比較數據是否爲有效數據
        if(strcmp(udp_datagram.data(),VALID_DATA) == 0)
        {
            //注意這裏的ip顯示的格式是這樣的,我們需要轉換一下"::ffff:192.168.xxx.xxx" ==> "192.168.xxx.xxx"
            QString ip_addr_temp =  udp_client_address.toString();
            QString ip_addr;
            int i = 0;
            //填充ip地址
            for(i = 7; ip_addr_temp[i] != '\0'; i ++ )
            {
                ip_addr[i-7] = ip_addr_temp[i];
            }
            //插入列表
            iot_dev_ip_item_add(ip_addr + QString(":")+ QString().number(udp_client_port),udp_datagram.data());
        }
        //非法數據,不處理

    }
}

//將獲取到的ip,加入到列表中
void MainWindow::iot_dev_ip_item_add(QString ip,QString data)
{
    //大於最大連接數,則不進行插入
    if(g_connect_count >= MAX_NUM)
        return ;
    //相同IP和端口,只顯示一個,這個值是不會重複的
    for(unsigned char i = 0; i < MAX_NUM; i ++)
    {
        if(ip == *ip_all[i])
        {
            //這裏添加調試信息打印
            qDebug() << "*****************************";
            qDebug() << "i = " << i;
            qDebug() << "buff:client_addr:" << *ip_all[i];
            qDebug() << "current client_addr:" << ip;

            return;
        }
    }
    //沒有找到相同的,插入
    ip_all[g_connect_count][0] = ip;
    g_connect_count = g_connect_count + 1;
    QListWidgetItem *list_iot_dev = new QListWidgetItem(ip + QString("\t") + data,ui->dev_infor_listWidget);
    ui->dev_infor_listWidget->insertItem(1,list_iot_dev);

}

void MainWindow::on_search_dev_pushButton_clicked()
{
   for(unsigned char i = 0; i < g_connect_count; i ++)
   {
       ip_all[i][0] = "";//清空緩衝區
   }
   g_connect_count = 0;
   ui->dev_infor_listWidget->clear();
   list_init();//重新初始化
}

測試情況如下:(測試客戶端使用通信貓,後續的話,我會將客戶端這部分的代碼進行補充,現在還沒有寫好)

運行程序,效果如下:

打開通信貓軟件,選擇udp,然後設置廣播的方式:

設計的知識歸納:

1.QT UDP的使用

2.QListWidget的使用

3.QListWidgetItem的使用

使用例子都在源代碼裏了。好好碼一次,加深理解即可~~~~

如果這篇文章,對你有幫助,就點個贊再走哈~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章