基于广播的设备搜索定位

该C++程序创建了一个UDP服务器,监听特定端口,接收私有协议的消息,然后响应。如果接收到特定消息,它会切换到TCP模式,接收和处理JSON数据,包括不同类型的操作如点表的获取和更新。QT客户端部分展示了如何使用QUdpSocket和QTcpSocket进行通信,搜索设备,发送不同类型的请求并解析接收到的JSON响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "cJSON.h"
#define N 2000

int main(int argc, char const *argv[])
{
    int broadfd;

    //./server <port> <protocol>
    if (argc < 3)
    {
        printf("usage: %s <port> <protocol>\n", argv[0]);
        return -1;
    }

    //创建一个socket文件描述符
    broadfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (broadfd < 0)
    {
        perror("sock err");
        return -1;
    }

    //绑定套接字(ip+port)
    struct sockaddr_in addr, cliaddr;
    ssize_t len;
    char buf[N] = {0};

    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[1])); //端口号
    //自动绑定所有的本机网卡的地址
    addr.sin_addr.s_addr = INADDR_ANY;

    int addrlen = sizeof(addr);

    //将套接字与所选ip绑定
    if (bind(broadfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    //接收消息,判断是否为私有协议
    while (1)
    {
        len = recvfrom(broadfd, buf, N, 0, (struct sockaddr *)&cliaddr, &addrlen);
        if (len > 0)
        {
            if (!strncmp(buf, argv[2], strlen(argv[2])))
            {
                printf("recv data=%s\n", buf);
                bzero(buf, N);
                strcpy(buf, "yes");
                sendto(broadfd, buf, N, 0, (struct sockaddr *)&cliaddr, addrlen);
                bzero(buf, N);
                break;
            }
            else
            {
                printf("包不正确\n");
                usleep(100000);
                continue;
            }
        }
        else
        {
            perror("recv err");
            exit(0);
        }
    }

    //建立服务器
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpfd < 0)
    {
        perror("sock2 err");
        return -1;
    }

    if (bind(tcpfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    if (listen(tcpfd, 5) < 0)
    {
        perror("listen err");
        return -1;
    }
    
    //接受客户端连接
    int clifd = accept(tcpfd, NULL, NULL);
    //int clifd = accept(tcpfd, (struct sockaddr *)&cliaddr, &addrlen);
    if (clifd < 0)
    {
        perror("accept err");
        return -1;
    }
    printf("accept succ\n");

    while (1)
    {
        bzero(buf, N);
        //usleep(1000000);
        read(clifd, buf, N);
        cJSON *root = cJSON_Parse(buf);
        if (NULL == root)
        {
            printf("Parse err\n");
            return -1;
        }
        bzero(buf, N);
        printf("%s\n", cJSON_Print(root)); //打印测试

        cJSON *type = cJSON_GetObjectItem(root, "type");
        if (!strncmp(type->valuestring, "1", 2))
        {
            if (access("./table.json", F_OK) == 0)
            {
                //电表存在
                printf("电表存在\n");
                strcpy(buf, "{\"type\": \"1\",\"result\": 0,\"up_config\": false,\"data\": {\"mqtt_config\": {\"mqtt_addr\": \"192.168.1.2\",\"mqtt_port\": 1883},\"video_config\": {\"video_addr\": \"192.168.8.8\",\"video_port\": 8888},\"update_config\": {\"type\": 1,\"period\": 5}}}");
                write(clifd, buf, strlen(buf));
                bzero(buf, N);
                usleep(3000000);

                //发送电表
                int fd = open("./table.json", O_RDONLY, 0666);
                int num = read(fd, buf, N);
                printf("点表字符个数:%d\n", num);
                write(clifd, buf, strlen(buf));
                bzero(buf, N);
                usleep(100000);

                
            }
            else
            {
                //创建JSON格式 发送数据
                strcpy(buf, "{\"type\": \"1\",\"result\": 1,\"up_config\": true}");
                write(clifd, buf, strlen(buf));
                bzero(buf, N);
                usleep(1000000);

                

              
                strcpy(buf, "./");
                strcat(buf, "table.json");
                int fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666);
                bzero(buf, N);

                

                // 将电表写进去
                int num = read(clifd, buf, N);
                printf("文件长度:%d\n", num);
                write(fd, buf, num + 1);
                close(fd);
                printf("%s\n", buf);
                bzero(buf, N);
                usleep(1000000);
                printf("点表接受成功\n");
               

               
            }
        }
        else if (!strncmp(type->valuestring, "2", 2))
        {
            strcpy(buf, "{\"type\": \"2\",\"result\": 1}");
            write(clifd, buf, strlen(buf));
            bzero(buf, N);
            usleep(1000000);
            //
            int fd = open("./table.json", O_WRONLY | O_CREAT | O_TRUNC, 0666);
            int num = read(clifd, buf, N);
            printf("读取字符个数:%d\n", num);
            if (write(fd, buf, strlen(buf)) < 0)
            {
                perror("write err221");
                return -1;
            }
            close(fd);
            bzero(buf, N);
            printf("点表接受成功\n");
            //
            // strcpy(buf, "{\"type\": 2,\"result\": 1}");
            // write(clifd, buf, strlen(buf) );
            // bzero(buf, N);
        }
        else if (!strncmp(type->valuestring, "3", 2))
        {
            strcpy(buf, "{\"type\": \"3\",\"result\": 1}");
            write(clifd, buf, strlen(buf));
            bzero(buf, N);
            usleep(100000);
        }
    }

    close(broadfd);
    close(tcpfd);
    close(clifd);
    return 0;
}

 

 

 

 

 

 

 QT客户端代码

#include "search_device.h"
#include "ui_search_device.h"
#include <QFile>

//type
//1:获取运行时必要的参数信息
//2:点表下发
//3:心跳包

Search_device::Search_device(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Search_device)
{
    ui->setupUi(this);

    //1.创建QUdpSocket对象
    UdpSocket = new QUdpSocket(this);

    //2.连接接收数据信号和槽
    connect(UdpSocket,SIGNAL(readyRead()),this,SLOT(on_pushButton_search_clicked()));//readRead()读取数据的信号

    //UDP接收协议,获得设备IP与port
    connect(UdpSocket,SIGNAL(readyRead()),this,SLOT(ReadyRead_Udp_Slots()));

    //创建TCP  Socket
    TCPsocket =new QTcpSocket(this);

    //点击IP,触发赋值槽函数;
    connect(ui->listWidget_search,SIGNAL(itemClicked(QListWidgetItem*)),
            this,SLOT(itemClickedIPSlot(QListWidgetItem*)));

    //点击port,触发赋值;
    connect(ui->listWidget_search,SIGNAL(itemClicked(QListWidgetItem*)),
            this,SLOT(itemClickedportSlot(QListWidgetItem*)));

    //点击连接按钮,与Tcp
    connect(ui->ConnectButton,SIGNAL(clicked()),this,SLOT(buttonConnectSlots()));

    //TCP通信
    connect(TCPsocket,SIGNAL(readyRead()),this,SLOT(ReadyRead_Tcp_Slots()));

    //发送 3种type类型
    connect(ui->pushButton_type,SIGNAL(clicked()),this,SLOT(type_send_Slots()));
}

Search_device::~Search_device()
{
    delete ui;
    delete TCPsocket;
    delete UdpSocket;
}



void Search_device::on_pushButton_search_clicked()
{

    //发送协议
    UdpSocket->writeDatagram("aaa",4,QHostAddress("192.168.50.255"),7777);//writeDatagrad()发送数据,参数:内容,大小,地址,端口

}

void Search_device::ReadyRead_Udp_Slots()
{

    QHostAddress myip;//获取ip
    quint16 myport;//获取端口
    QByteArray data;
    while(UdpSocket->hasPendingDatagrams())    //匹配到对应的设备,并接收到设备返回的“yes”
    {

        data.resize(UdpSocket->pendingDatagramSize());
        UdpSocket->readDatagram(data.data(),data.size(),&myip,&myport);

        QString buf = data.data();
        if(buf == "yes")
        {

            ui->listWidget_search->addItem(myip.toString()+"and"+QString::number(myport));

        }

    }

}

void Search_device::itemClickedIPSlot(QListWidgetItem *item)
{
    ip=item->text().left(13);
    qDebug() << "ip:" ;
    qDebug() << ip <<endl;
}

void Search_device::itemClickedportSlot(QListWidgetItem *item)
{
    port=item->text().right(4).toInt();
    qDebug() << "port:" ;
    qDebug() << port <<endl;
}

void Search_device::buttonConnectSlots()
{

    // 发起TCP连接请求
    qDebug() << "发起请求连接" ;
    TCPsocket->connectToHost(ip,port,QIODevice::ReadWrite);//QIODevice类是所有输入/输出设备的基类而QIODevice::ReadWrite则表示该设备既可以读取数据,也可以写入数据。
    qDebug() << "连接已完成" ;
    qDebug() << ip <<86;
    qDebug() << port <<87;
}

void Search_device::type_send_Slots()
{
    QJsonObject json;//创建json对象
    QTextStream output(TCPsocket);//用于创建一个QTextStream对象,用于输出文本数据。它返回一个QTextStream对象,你可以使用该对象来写入数据到输出设备,如控制台、文件或网络套接字
    if(ui->comboBox->currentText() == "1")
    {
        json.insert("type","1");
        QJsonDocument doc(json);//QJsonDocument是Qt中用于处理JSON文档的类,它提供了创建、读取、写入和操作JSON数据的方法。
        output << doc.toJson();//toJson()将JSON文档转换为字符串
        qDebug() << doc.toJson();
    }
    else if(ui->comboBox->currentText() == "2")
    {
        json.insert("type","2");
        QJsonDocument doc(json);//QJsonDocument是Qt中用于处理JSON文档的类,它提供了创建、读取、写入和操作JSON数据的方法。
        output << doc.toJson();//toJson()将JSON文档转换为字符串
        qDebug() << doc.toJson();
    }
    else if(ui->comboBox->currentText() == "3")
    {
        json.insert("type","3");
        QJsonDocument doc(json);//QJsonDocument是Qt中用于处理JSON文档的类,它提供了创建、读取、写入和操作JSON数据的方法。
        output << doc.toJson();//toJson()将JSON文档转换为字符串
        qDebug() << doc.toJson();
    }
}
void Search_device::ReadyRead_Tcp_Slots()
{
    qDebug() << "有消息到了"<<endl;

    QByteArray Tcpdata = TCPsocket->readAll();    //把接收到网关发来的数据全部读到Tcpdata里面;
    QString buff = Tcpdata; //消息转字符串

    qDebug() << buff <<endl;
    QJsonParseError err;
    QJsonDocument jsonMsg(QJsonDocument::fromJson(buff.toLatin1(),&err));//fromJson()函数用于将JSON格式的字符串转换为QJsonDocument对象
    if(err.error != QJsonParseError::NoError)
    {
        qDebug() << "Json格式错误!!";
        return;
    }
        QJsonObject Json = jsonMsg.object();//.object获取QJsonDocument对象中的根级别的QJsonObject
        if(Json.value("version") != QJsonValue::Undefined)
        {
            QString version = Json.value("version").toString();
            ui->textBrowser->setText(version);
            return;
        }
        QString type = Json.value("type").toString();
        //buff.append("type:");
        buff.clear();
        if(type == "1")
        {
            QString up_config = Json.value("up_config").toString();
            if(up_config == "true")
            {
                qDebug() << "没有点表,需要下发点表!!";
                ui->listWidget->clear();
                ui->listWidget->addItem("没有点表,需要下发点表!");
                //QJsonObject json;

                // 弹窗
                QString filter = "视频(*.mp4 *.avi);;所有文件(*)";
                con:
                QString path = QFileDialog::getOpenFileName(this,"没有点表,需要下发点表!","F:/",filter);
                // 判断选择有效性
                if(path == "" && readPath == "")
                {
                    QMessageBox::warning(this,"提示","请选择要读取的文件!");
                    goto con;
                }
                readPath = path;
                // 显示
                ui->textBrowser->clear();
                ui->textBrowser->append(readPath);

                QFile readFile(readPath);
                readFile.open(QIODevice::ReadOnly);
                // 获得可读的数据量
                qint64 total = readFile.size();
                // 字节数组类
                QByteArray buffer;
                buffer = readFile.read(total+1);
                //QString buff = buffer;

//                json.insert("type","2");
//                QJsonObject data;
//                data.insert("file_name","table.json");
//                data.insert("flag","start");
//                data.insert("file_len",560);
//                json.insert("data",data);


                //QJsonDocument document(json);          //转化成JSON字符串
                //QByteArray aaa = document.toJson();   //放入数组aaa中

                TCPsocket->write(buffer);         //TCP发送
                TCPsocket->flush();


            }
            else if(up_config == "false")
            {
                qDebug()<<"有点表,不需要下发!";
                ui->listWidget->clear();
                ui->listWidget->addItem("有点表,不需要下发点表,点表信息已显示");
                ui->textBrowser->clear();
                ui->textBrowser->append((buff=TCPsocket->readAll()));
//                QJsonObject json3;
//                json3.insert("type","3");
//                QJsonDocument document1(json3);
//                QByteArray bbb = document1.toJson();

//                TCPsocket->write(bbb);
//                TCPsocket->flush();

//                ui->listWidget->clear();
//                ui->listWidget->addItem("心跳包已连接");
                buff.clear();
            }
        }
        else if(type == "2")        //下发点表
        {
//            QJsonObject Json2 = Json.value("data").toObject();
//            QString flag = Json2.value("flag").toString();

//            if(flag == "start")
//            {
            // 弹窗
            QString filter = "所有文件(*)";
            ccon:
            QString path = QFileDialog::getOpenFileName(this,"没有点表,需要下发点表!","F:/",filter);
            // 判断选择有效性
            if(path == "" && readPath == "")
            {
                QMessageBox::warning(this,"提示","请选择要读取的文件!");
                goto ccon;
            }
            readPath = path;
            // 显示在QTextBrowser
            ui->textBrowser->append(readPath);

            QFile readFile(readPath);
            readFile.open(QIODevice::ReadOnly);
            // 获得可读的数据量
            qint64 total = readFile.size();
            // 字节数组类
            QByteArray buffer;
            buffer = readFile.read(total+1);
                //打开JSON文件
                //QFile loadFile("D:/node.json");

//                if(!loadFile.open(QIODevice::ReadOnly))
//                {
//                    qDebug() << "could't open projects json";
//                    return;
//                }

                //QByteArray allData = loadFile.readAll();

                // QString buf = allData;
                // QTextStream output(mytcpsocket);
                //TCPsocket->write(allData,560);  //TCP发送
            TCPsocket->write(buffer);         //TCP发送
            TCPsocket->flush();
        }
        else if(type == "3")
        {
//            QJsonObject json5;
//            json5.insert("type","3");
//            QJsonDocument document3(json5);
//            QByteArray ddd = document3.toJson();

//            TCPsocket->write(ddd);
//            TCPsocket->flush();

            ui->listWidget->clear();
            ui->listWidget->addItem("心跳包已连接 网关在线");
        }
}












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值