QT開發的即時通訊軟體(基於UDP)

csu_zhengzy~發表於2018-11-21

這是本人在學習QT和計算機網路的時候自己開發的UDP網路通訊軟體,可收可發,可作為服務端也可以作為客戶端,並可以使用mysql資料庫儲存歷史記錄,親測可用,註釋詳細,歡迎參考,先上圖,原始碼附在下面,也可以直接在這下載:https://download.csdn.net/download/qq_18108083/10798364 賺點積分,我一點也沒有,謝謝,嘿嘿~

(1).main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF8"));  //保證正常顯示中文
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF8"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF8"));

    QApplication a(argc, argv);
    MainWindow w;

    w.show();
    w.connectDatabase();    //連線資料庫

    return a.exec();
}

(2).mainwindow.cpp

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

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

//    QPalette palette;   //設定視窗顏色
//    palette.setBrush(this->backgroundRole(), Qt::lightGray);
//    this->setPalette(palette);

    timer =new QTimer(this);  //建立定時器
    receiveCount=0;  //接收區計數初始化
    sendCount=0;     //傳送區計數

    QObject::connect(ui->sendPushButton,SIGNAL(clicked(bool)),this,SLOT(sendUdpSlot()));  //傳送upd
    QObject::connect(ui->clearReceivePushButton,SIGNAL(clicked(bool)),this,SLOT(clearReceiveSlot()));  //清空接收區
    QObject::connect(ui->autoSendCheckBox,SIGNAL(stateChanged(int)),this,SLOT(setAutoSendSlot()));     //自動傳送 開關定時器
    QObject::connect(this->timer,SIGNAL(timeout()),this,SLOT(sendUdpSlot()));    //自動傳送延時溢位
    QObject::connect(ui->delayTimeLineEdit,SIGNAL(returnPressed()),this,SLOT(setAutoSendSlot()));   //定時line回車
    QObject::connect(ui->saveLocalIpPushButton,SIGNAL(clicked(bool)),this,SLOT(saveNetworkSetSlot()));  //儲存設定

    QObject::connect(ui->showHistoryPushButton,SIGNAL(clicked(bool)),this,SLOT(showUdpRecordSlot()));  //顯示歷史訊息記錄
    QObject::connect(ui->clearHistoryPushButton,SIGNAL(clicked(bool)),this,SLOT(clearDatabaseSlot())); //清除資料庫

    //對於接收來說只需要監聽埠即可

    //bind(10000,QAbstractSocket::DontShareAddress);bind(port);

    //對於傳送來說
    /*
        //udpSocket->writeDatagram(傳送的資料,傳送資料的長度,IP,埠); 返回一個長度.
        len=udpSocket->writeDatagram(text.toLatin1(),text.length(),QHostAddress::LocalHost,port);
    */

    uSocket=new QUdpSocket;
    /*列印本地IP QHostAddress::LocalHost*/
    ui->receiveContextTextEdit->append("******************************************************");
    ui->receiveContextTextEdit->append("    本地IP");
    ui->receiveContextTextEdit->append("******************************************************");
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    foreach (QHostAddress address, list)
    {
       if(address.protocol() == QAbstractSocket::IPv4Protocol)  //使用IPv4地址
       ui->receiveContextTextEdit->append(address.toString());
    }
    ui->receiveContextTextEdit->append("******************************************************");


    /*程式啟動時初始化網路設定*/
    QString listenip=ui->listenIpLineEdit->text();  //獲取監聽的本地ip
    quint16 listenport=quint16(ui->listenPortLineEdit->text().toUInt());  //獲取監聽埠//////////////////////////後面要更改設定


    uSocket->bind(QHostAddress(listenip),listenport); //繫結埠   ,繫結後一般不再更改
    //uSocket->bind(QHostAddress("192.168.1.33"),quint16(63392)); //繫結埠   ,繫結後一般不再更改
   connect(uSocket,SIGNAL(readyRead()),this,SLOT(receiveUdpSlot()));  //在收到資料以後,SOCKET觸發事件
}

MainWindow::~MainWindow()
{
    delete ui;
    delete uSocket;  //清理記憶體
}


void MainWindow::receiveUdpSlot()
{

    while(uSocket->hasPendingDatagrams())   //有掛起的資料
    {
        QByteArray receiveData;                                         //因為傳來的資料型別是未知的,用bytearray型別
        receiveData.resize(uSocket->pendingDatagramSize());             //receiveData的資料大小取決於接收到的資料
        uSocket->readDatagram(receiveData.data(),receiveData.size());   //讀取資料

        if(!ui->stopShowCheckBox->isChecked())                          //停止重新整理接收區未被選中
        {

            QDateTime currentTime=QDateTime::currentDateTime();  //獲取當前時間
            QString curTime=currentTime.toString("hh.mm.ss"); //將時間轉換成字串格式(按格式)

            if(ui->showTimeCheckBox->isChecked())                       //顯示時間戳被選中
            {
                ui->receiveContextTextEdit->append("# "+curTime+":");  //追加文字框中的內容 append是從新的一行列印
            }
            ui->receiveContextTextEdit->append(QString::fromUtf8(receiveData)); //新增文字
            ui->receiveContextTextEdit->scrollBarWidgets(Qt::AlignBottom);      //滾輪自動移動到末端        
            receiveCount+=receiveData.count();  //更新接收計數值
            ui->receiveCountLabel->setText(QVariant(receiveCount).toString());

            MainWindow::insertDataToDb(curTime,QString::fromUtf8(receiveData));  //往資料庫中插入
        }

    }
}
void MainWindow::sendUdpSlot()      //傳送Udp訊號槽(傳送按鈕觸發,時間溢位觸發)
{
    QString sendip=ui->ipLineEdit->text();   //獲取目標ip
    quint16 sendport=quint16(ui->portLineEdit->text().toUInt());  //獲取目標埠

    QString sendContext=ui->sendcontextTextEdit->document()->toPlainText();
    uSocket->writeDatagram(sendContext.toUtf8(),QHostAddress(sendip),quint16(sendport));  //往 IP+prot上 發生資料
    sendCount+=sendContext.count();//更新傳送計數值
    ui->sendCountLabel->setText(QVariant(sendCount).toString());
/*
    //QUdpSocket qus;   //定義一個UDP
    QString myMessage = "I' UDP Server";

    for(int i=0;i<100;i++)   //傳送100次
    {
        uSocket->writeDatagram(myMessage.toUtf8(),QHostAddress("192.168.37.129"),quint16(8000));  //往 IP+prot上 發生資料
        std::cout<<"server send"<<std::endl;
    }
*/
}
void MainWindow::clearReceiveSlot() //清空接收區
{
    ui->receiveContextTextEdit->clear();
    receiveCount=0;  //更新接收計數值
    ui->receiveCountLabel->setText(QVariant(receiveCount).toString());
}
void MainWindow::setAutoSendSlot()     //設定自動傳送(剛被勾選時觸發,時間line回車)
{
    this->timer->stop();  //首先關閉定時器
    if(ui->autoSendCheckBox->isChecked())  //如果自動傳送被選中
    {
        if((!ui->delayTimeLineEdit->text().isEmpty())&&ui->delayTimeLineEdit->text().toLong()!=0)  //如果時間間隔非空且自動轉整數後不為0
        {
            this->timer->start(ui->delayTimeLineEdit->text().toLong());   //開啟定時器  單位毫秒
        }
        else  // 傳送區空
        {
            ui->autoSendCheckBox->setCheckState(Qt::Unchecked);    //強行設定未被勾選
            QMessageBox::information(this,"提示:","未成功設定時間間隔");
            return;
        }

    }
    else
    {
        this->timer->stop();
    }
}
void MainWindow::saveNetworkSetSlot()   // 儲存設定
{

    QMessageBox::information(this,"提示:","尚未開發");
}
void MainWindow::connectDatabase()    //成員函式:連線資料庫
{
    db=QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("localhost");
    db.setDatabaseName("udpdatabase");
    db.setUserName("root");
    db.setPassword("020513");
    bool ok = db.open();
    if(ok)
    {
        qDebug()<<"open success";    //連線資料庫成功
        QMessageBox::information(this,"提示","成功連線資料庫");
        ui->databaseStatusLabel->setText("已連線");

        QPalette palette;            //設定字型顏色
        palette.setColor(QPalette::WindowText,Qt::green);
        ui->databaseStatusLabel->setPalette(palette);
    }
    else
    {
        qDebug()<<"open error"<<this->db.lastError().text();
        QMessageBox::information(this,"連線失敗",this->db.lastError().text());
        ui->databaseStatusLabel->setText("未連線");

        QPalette palette;            //設定字型顏色
        palette.setColor(QPalette::WindowText,Qt::red);
        ui->databaseStatusLabel->setPalette(palette);
    }
}
void MainWindow::showUdpRecordSlot()  //顯示訊息記錄QString time,QString udpMessage
{
    if(this->db.isOpen())
    {
    QSqlQuery query;
    query.exec("select * from message;");
    while (query.next())
    {
        QString time = query.value(0).toString();
        QString message= query.value(1).toString();
        ui->receiveContextTextEdit->append(time+"               "+message);
    }
    }
}
void MainWindow::insertDataToDb(QString time,QString message)  //往資料庫中插入資料
{
    //加上連線資料庫狀態判斷
    if(this->db.isOpen())
    {
        QSqlQuery query;
        query.prepare("INSERT INTO message (time, udpmessage) "
                      "VALUES (:time, :udpmessage)");
        query.bindValue(":time", time);
        query.bindValue(":udpmessage", message);
        query.exec();
        qDebug()<<"成功插入資料";
    }
}
void MainWindow::clearDatabaseSlot()    //清空資料庫記錄
{
    if(this->db.isOpen())
    {
        QSqlQuery query;
        query.exec("truncate table message");
        QMessageBox::information(this,"提示","成功清除歷史記錄");
    }
}

(3).mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUdpSocket>
#include <QTextCodec>//保證正常顯示中文
#include <QHostAddress>
#include <QHostInfo>
#include <QNetworkInterface>
#include <iostream>   //std ::cout
#include <QByteArray>
#include <QCoreApplication>
#include <QDateTime>
#include <Qpalette>
#include <QTimer>    //定時器
#include <QMessageBox>
#include <QtSql>     //sql資料庫
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    void connectDatabase();    //連線資料庫
    void insertDataToDb(QString,QString);  //往資料庫中插入資料
private:
    Ui::MainWindow *ui;
    quint64 receiveCount;  //接收區計數
    quint64 sendCount;     //傳送區計數

    QTimer *timer;   //定義定時器指標
    QUdpSocket *uSocket;   //因為要在槽函式中使用,因此在這裡定義

    QSqlDatabase db;  //定義一個全域性的資料庫

private slots:
    void receiveUdpSlot();   //槽函式用於對接受的資料進行處理

    void sendUdpSlot();      //傳送Udp訊號槽(傳送按鈕觸發)
    void clearReceiveSlot();   //清空接收區
    void saveNetworkSetSlot(); //儲存網路設定
    void setAutoSendSlot();    //設定自動傳送,開啟定時器(剛被勾選時觸發,時間line回車)

    void showUdpRecordSlot();  //顯示訊息記錄
    void clearDatabaseSlot();  //清空資料庫記錄
};

#endif // MAINWINDOW_H

 

相關文章