初探Qt与Udp

写在前面

最近由于工作需要,需要用Qt写一个udp通信的程序,这个udp程序只用来接收数据,不发送(等之后需要发送数据了在进行补充)于是就有了下面一个程序,我先将功能部分拆解,然后之后会将所有的源码放在下面,有需要的可以直接拷贝到下面,写这篇文章主要是为了分享给有需要的人,同时也记录下来方便自己以后回忆。

实现的主要功能

点击连接网络,会将本地的IP自动分配一个,然后建立连接,此时状态会显示建立udp连接成功,同时会在本地文件夹中生成一个
.log文件,这个文件作为日志文件,之后会将接收的数据放到log日志文件中去。清空显示则是清空接收。 接收计数则是显示接收的数据数量(具体的数据格式与数量之间的关系自己去算一下吧~)
在这里插入图片描述

功能实现

获取ip

在这里插入图片描述

连接udp

在这里插入图片描述

生成log文件

在这里插入图片描述
在这里插入图片描述

判断字符串格式

因为工作需要,需要判断一些错误,将含有ERR的字符串设置为红色,其余设置为绿色。

        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(), datagram.size(), &address, &port);
        tmpIPPort =QHostAddress(address.toIPv4Address()).toString()+ ":" + QString::number(port, 10);
        QString rcvMsg  = QString::fromUtf8(datagram, datagram.size());
        if(CurIPPort != tmpIPPort) {
            CurIPPort = tmpIPPort;
            //            if(ui->ReceiveTextEdit->toPlainText().size() == 0) {
            //            ui->ReceiveTextEdit->moveCursor(QTextCursor::Start);
            //            }
            // 设置文本颜色
            QTextCharFormat fmt;
            fmt.setForeground(Qt::green);
            ui->ReceiveTextEdit->mergeCurrentCharFormat(fmt);
            ui->ReceiveTextEdit->appendPlainText(tr("【数据来自") + CurIPPort + tr("】")+"\n");   //添加数据  192.~
            rcvDataCnt += datagram.size();
            ui->lEdit_RcvCnt->setText(QString::number(rcvDataCnt, 10));      
        }
        //        // 设置文本颜色
        //        QTextCharFormat fmt;
        //        fmt.setForeground(Qt::green);
        int index = 0;
        QTextCharFormat fmt;
        
        while(index<rcvMsg.size()){
            if(rcvMsg.mid(index).toLower().contains("err")){
                fmt.setForeground(Qt::red);
                // qDebug()<<"进入红色";
                break;
            }
            else{
                fmt.setForeground(Qt::green);
                //  qDebug()<<"进入绿色";
            }
            index++;
        }
        
        if(ui->ReceiveTextEdit->toPlainText().size() == 0) {
            ui->ReceiveTextEdit->moveCursor(QTextCursor::Start);
            ui->ReceiveTextEdit->mergeCurrentCharFormat(fmt);
            ui->ReceiveTextEdit->insertPlainText(rcvMsg);
            // qDebug()<<rcvMsg;
        }else{
            // 插入文本
            ui->ReceiveTextEdit->moveCursor(QTextCursor::End);
            ui->ReceiveTextEdit->mergeCurrentCharFormat(fmt);
            ui->ReceiveTextEdit->insertPlainText(rcvMsg);
        }

使用Plaintextedit的insertPlainText方法设置不会拖动而重复行

在我们使用plaintextedit的insertPlainText方法的时候有时候鼠标光标移动会让内容错行,虽然可以使用appendPlainText方法防止移动,但是append方法会自动换行,这就让人很是难受,所以需要通过设置方法来设置这些问题。

  //在界面初始化的时候将plaintextedit设置成这个
   ui->ReceiveTextEdit->ensureCursorVisible();
   ui->ReceiveTextEdit->setReadOnly(true);

用光标这样会有一个Bug就是在你使用clear方法的时候,你在接收数据界面是不会显示的,就很让人难过,于是我通过在使用clear方法之后重新设置一下光标就可以了。
在这里插入图片描述

界面实现效果

在这里插入图片描述
.log文件
在这里插入图片描述

源码

.pro文件

#-------------------------------------------------
#
# Project created by QtCreator 2014-04-10T19:21:07
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = NetAssistant
target.path=/usr/local/bin
INSTALLS=target

TEMPLATE = app


SOURCES += main.cpp\
    mainwindow.cpp

HEADERS  += \
    define.h \
    mainwindow.h

FORMS    += \
    mainwindow.ui

RESOURCES += \
    qrc.qrc

QT  +=network

RC_FILE += icon.rc

DISTFILES += \
    android/AndroidManifest.xml

TRANSLATIONS += language/English.ts \
                language/Chinese.ts

ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android

.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtNetwork>
#include <QDataStream>
#include <QTextStream>


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    void setUdpGuiExt();
    void setTcpSvrGuiExt();
    void setTcpClientGuiExt();

    QList<int> tcpClientSocketDescriptorList;
    int TcpClientLinkCnt;
    QString logFilePath;

signals:
    void sendDataToClient(char *msg, int length, int socketDescriptor, int socketDescriptorEx);

private slots:

    void on_pBtnNetCnnt_clicked(bool checked);

    void on_pBtnResetCnt_clicked();
    char ConvertHexChar(char ch);
    char ConvertHexStr(QString hexSubStr);

    //=======UDP========
    void udpDataReceived();









    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    QString m_ip;
    //-----UDP-----
    QUdpSocket *udpSocket;
    QHostAddress lhAddr;
    int lhPort;
    QHostAddress rmtAddr;
    int rmtPort;



    //Global state
    unsigned int rcvDataCnt;
    unsigned int sndDataCnt;
    //bool NetState;
    QTimer *timer;
    bool loopSending;

    QString CurIPPort;

    QString CurPath;
    QFile *curFile;

    QTranslator translator;
};

#endif // MAINWINDOW_H

.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTranslator>

#include "define.h"
#include <QMessageBox>
#include <stdlib.h>
#include <QString>
#include <QTimer>
#include <QInputDialog>
#include <QDateTime>
#include <QFile>
#include <QDateTime>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->ReceiveTextEdit->ensureCursorVisible();
    ui->ReceiveTextEdit->setReadOnly(true);


    //设置程序的开启默认画面
    setUdpGuiExt();


    /*创建.log文件*/
    QString logFileName = "logfile.log";  // 日志文件名
    // 获取当前应用程序所在的目录
    QString currentPath = QCoreApplication::applicationDirPath();
    // 拼接日志文件的完整路径
    logFilePath = currentPath + "/" + logFileName;

    if (!QFile::exists(logFilePath)) {
        QFile logFile(logFilePath);
        if (logFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            logFile.close();
            ui->label->setText("日志文件已生成");
            qDebug() << "Log file created.";
        } else {
            ui->label->setText("日志文件生成失败");
            qDebug() << "Failed to create log file.";
            // 处理文件创建失败的情况
        }
    }
    else{
        ui->label->setText("日志文件已存在");
    }



    //获取本机的IP地址,并初始化相应的控件属性和变量
    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    // use the first non-localhost IPv4 address
    for(int i = 0; i < ipAddressesList.size(); ++i) {
        if(ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address()) {
            m_ip = ipAddressesList.at(i).toString();
            break;
        }
    }
    // 设置获取的IP到相应文本框
    //ui->lEditIpAddr->setText(m_ip);
    // ui->lEditUdpIP->setText(m_ip);


    //初始化全局变量
    rcvDataCnt  = 0;
    sndDataCnt = 0;
    TcpClientLinkCnt = 0;
    //NetState = false;
    loopSending = false;
    CurIPPort = "";
    CurPath = "";
    curFile = 0;
}

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

/**********************************************************/
//Function for connection button
void MainWindow::on_pBtnNetCnnt_clicked(bool checked)
{
    if(checked) {     //切换到链接状态
        //建立UDP链接
        udpSocket = new QUdpSocket(this);
        connect(udpSocket, SIGNAL(readyRead()), this, SLOT(udpDataReceived()));
        lhAddr.setAddress(m_ip);
        lhPort =1686;
        rmtAddr.setAddress("192.168.1.16");
        rmtPort = 1689;
        bool result = udpSocket->bind(lhPort);
        if(!result)
        {
            ui->pBtnNetCnnt->setChecked(0);
            QMessageBox::information(this, tr("错误"), tr("UDP绑定端口失败!"));
            return;
        }
        ui->CurState->setText(tr("建立UDP连接成功"));


        ui->pBtnNetCnnt->setText(tr("断开网络"));
        //NetState = true;
    } else { //切换到断开状态

        //断开UDP链接
        udpSocket->close();
        delete udpSocket;

        ui->pBtnNetCnnt->setText(tr("连接网络"));
        ui->CurState->setText(tr(""));
        // NetState = false;
    }
}


/**********************************************************/
//set UDP mode
void MainWindow::setUdpGuiExt()
{
    // ui->labelSpaceUdp->setVisible(true);
    //    ui->lEditUdpIP->setVisible(true);
    //    ui->labelUdp->setVisible(true);
    //    ui->labelUdp1->setVisible(true);
    //    ui->lEditUdpPort->setVisible(true);
    // ui->labelSpaceClients->setVisible(false);

}

/**********************************************************/
//udp data received
void MainWindow::udpDataReceived()
{
    QHostAddress address;
    quint16 port;
    QString tmpIPPort = "";

    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(), datagram.size(), &address, &port);
        tmpIPPort =QHostAddress(address.toIPv4Address()).toString()+ ":" + QString::number(port, 10);
        QString rcvMsg  = QString::fromUtf8(datagram, datagram.size());
        if(CurIPPort != tmpIPPort) {
            CurIPPort = tmpIPPort;
            //            if(ui->ReceiveTextEdit->toPlainText().size() == 0) {
            //            ui->ReceiveTextEdit->moveCursor(QTextCursor::Start);
            //            }
            // 设置文本颜色
            QTextCharFormat fmt;
            fmt.setForeground(Qt::green);
            ui->ReceiveTextEdit->mergeCurrentCharFormat(fmt);
            ui->ReceiveTextEdit->appendPlainText(tr("【数据来自") + CurIPPort + tr("】")+"\n");   //添加数据  192.~
            rcvDataCnt += datagram.size();
            ui->lEdit_RcvCnt->setText(QString::number(rcvDataCnt, 10));
        }
        //        // 设置文本颜色
        //        QTextCharFormat fmt;
        //        fmt.setForeground(Qt::green);
        int index = 0;
        QTextCharFormat fmt;

        while(index<rcvMsg.size()){
            if(rcvMsg.mid(index).toLower().contains("err")){
                fmt.setForeground(Qt::red);
                // qDebug()<<"进入红色";
                break;
            }
            else{
                fmt.setForeground(Qt::green);
                //  qDebug()<<"进入绿色";
            }
            index++;
        }

        if(ui->ReceiveTextEdit->toPlainText().size() == 0) {
            ui->ReceiveTextEdit->moveCursor(QTextCursor::Start);
            ui->ReceiveTextEdit->mergeCurrentCharFormat(fmt);
            ui->ReceiveTextEdit->insertPlainText(rcvMsg);
            // qDebug()<<rcvMsg;
        }else{
            // 插入文本
            ui->ReceiveTextEdit->moveCursor(QTextCursor::End);
            ui->ReceiveTextEdit->mergeCurrentCharFormat(fmt);
            ui->ReceiveTextEdit->insertPlainText(rcvMsg);
        }

        /*输出到.log文件中*/
        QFile logFile(logFilePath);
        if (logFile.open(QIODevice::Append | QIODevice::Text)) {
            QTextStream logStream(&logFile);
            logStream << QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss] ")
                      << rcvMsg ;
            logFile.close();
        } else {
            qDebug() << "Failed to open log file for writing.";
            // 处理日志文件写入失败的情况
        }




        // ui->ReceiveTextEdit->insertPlainText(rcvMsg);
        // ui->ReceiveTextEdit->appendPlainText(rcvMsg);
        //ui->ReceiveTextEdit->insertPlainText("\n");
        //ui->ReceiveTextEdit->ensureCursorVisible();

        //接收计数增加
        rcvDataCnt += datagram.size();
        ui->lEdit_RcvCnt->setText(QString::number(rcvDataCnt, 10));
    }

}


/**********************************************************/
//reset the conters
void MainWindow::on_pBtnResetCnt_clicked()
{
    sndDataCnt = 0;
    rcvDataCnt = 0;
    ui->lEdit_RcvCnt->setText(QString::number(0, 10));

}

/***********************************************/
//转化十六进制中的字符到ASCII
char MainWindow::ConvertHexChar(char ch)

{
    if((ch >= '0') && (ch <= '9'))
        return ch - 0x30;
    else if((ch >= 'A') && (ch <= 'F'))
        return ch - 'A' + 10;
    else if((ch >= 'a') && (ch <= 'f'))
        return ch - 'a' + 10;
    else return (-1);
}

/***********************************************/
//转化十六进制字符到ASCII字母
char MainWindow::ConvertHexStr(QString hexSubStr)
{
    char ch = 0;
    if(hexSubStr.length() == 2) {
        // ch =  ConvertHexChar(hexSubStr.at(0).toAscii())*16+ ConvertHexChar(hexSubStr.at(1).toAscii()); //qt4.8
        ch =  ConvertHexChar(hexSubStr.at(0).toLatin1()) * 16 + ConvertHexChar(hexSubStr.at(1).toLatin1());
    } else if(hexSubStr.length() == 1) {
        //ch =  ConvertHexChar(hexSubStr.at(0).toAscii());  //qt4.8
        ch =  ConvertHexChar(hexSubStr.at(0).toLatin1());
    }
    return ch;
}



void MainWindow::on_pushButton_clicked()
{
    ui->ReceiveTextEdit->clear();

}


.ui文件

在这里插入图片描述

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值