Qt TCP和UDP通信及线程介绍

一.UDP介绍

UDP(User Datagram Protocol,用户数据报协议)

UDP是一个轻量级、不可靠、面向数据报的、无连接的协议,多用于可靠性要求不严格,不是非常重要的传输。

QUdpSocket类继承自QAbstractSocket,用来发送和接收UDP数据报,"Socket"即套接字,套接字即IP地址+端口号。其中IP地址指定了网络中的一台主机,二端口号则指定了该主机上的一个网络程序,使用套接字即可实现网络上的两个应用程序之间的通信。

QUdpSocket支持IPv4广播,要广播数据报,则只需发送到一个特殊的地址QHostAddress::Broadcast(即255.255.255.255),数据报一般建议发送字节数小于512字节。端口号选择1024-65535(1024以下的常用作保留端口号,如FTP常用端口号21,Telnet常用端口号23,DNS域名服务器常用端口53等)。

发送端

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    m_sender=new QUdpSocket(this);

}

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

void MainWindow::on_pushButton_clicked()
{
    QByteArray dataGram=ui->lineEdit->text().toUtf8();
    m_sender->writeDatagram(dataGram.data(),
                            dataGram.size(),
                            QHostAddress::Broadcast,
                            6666);

}

接收端

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    m_receiver=new QUdpSocket(this);

    m_receiver->bind(6666,QUdpSocket::ShareAddress);
    connect(m_receiver,&QUdpSocket::readyRead,this,&MainWindow::processData);
}

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

void MainWindow::processData()
{
    QString strData;

    //有未处理的数据包
    while(m_receiver->hasPendingDatagrams())
    {
        QByteArray dataGram;
        dataGram.resize(m_receiver->pendingDatagramSize());

        m_receiver->readDatagram(dataGram.data(),dataGram.size());

        ui->label_2->setText(dataGram);
    }
}

二.TCP介绍

TCP(Transmission Control Protocol,传输控制协议)

TCP是一个用于数据传输的地城网络协议,多个网络协议包括(HTTP和FTP都是基于TCP协议),TCP是面向数据流和连接的可靠的传输协议。

QTcpSocket继承自QAbstractSocket,与QUdpSocket传输的数据报不同的是,QTcpSocket传输的是连续的数据流,尤其适合连续的数据传输,TCP一般分为客户端和服务端,即C/S (Client/Server模型)。

QTcpSocket代表了两个独立的数据流,一个用来读取数据,一个用来写入数据,分别采用QTcpSocket::read()及QTcpSocket::write()操作,读取数据前先调用QTcpSocket::bytesAvailable来确定已有足够的数据可用。

QTcpServer处理客户端的连接,可通过QTcpServer::listen()监听客户端发来的连接请求,每当有客户端连接时会发射newConnection()信号,QTcpSocket可用于读取客户端发来的数据报,亦可发送数据报。

客户端

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

const int gTcpPort =8888;

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

    m_tcpSocket=new QTcpSocket(this);

    //socket有数据来了,做处理
    connect(m_tcpSocket,&QTcpSocket::readyRead,this,
            &MainWindow::onReadMessage);

    connect(m_tcpSocket,SIGNAL(SocketError(QAbstractSocket::SocketError)),
            this,SLOT(onDisplayError(QAbstractSocket::SocketError)));
    ui->lineEdit_host->setText("127.0.0.1");
    ui->lineEdit_port->setText(QString::number(gTcpPort));

}

void MainWindow::onReadMessage()
{
    //读取信息
    QByteArray bt;
    bt.resize( m_tcpSocket->bytesAvailable());

    m_tcpSocket->read(bt.data(),bt.size());

    ui->label_receive->setText(bt);
}

void MainWindow::onDisplayError(QAbstractSocket::SocketError error)
{
    //显示错误信息
    qDebug()<<"socketError:"<<error<<endl
           <<m_tcpSocket->errorString();
}

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

void MainWindow::on_pushButton_connect_clicked()
{
    //终止socket
    m_tcpSocket->abort();

    //connectToHost(IP,Port)
    m_tcpSocket->connectToHost(ui->lineEdit_host->text(),
                               ui->lineEdit_port->text().toInt());


}

void MainWindow::on_pushButton_send_clicked()
{
    m_tcpSocket->write(ui->lineEdit_send->text().toUtf8());
    m_tcpSocket->flush();
}

服务端

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QDebug>

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

    m_tcpserver=new QTcpServer(this);

    //开始监听客户端发来的请求
    if(!m_tcpserver->listen(QHostAddress::Any,8888))
    {
        qDebug()<<m_tcpserver->errorString();
        close();
    }

    connect(m_tcpserver,&QTcpServer::newConnection,
            this,&MainWindow::onNewConnect);

    connect(m_tcpserver,&QTcpServer::newConnection,
            this,&MainWindow::onsendMessage);

}

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

void MainWindow::onNewConnect()
{
    //客户端新的连接处理

    //当前连接的对象
    m_tcpsocket=m_tcpserver->nextPendingConnection();

    //如果断开连接自动销毁资源
    connect(m_tcpsocket,&QTcpSocket::disconnected,this,
            &QTcpSocket::deleteLater);

    //socket有数据时,会发射readRead信号
    connect(m_tcpsocket,&QTcpSocket::readyRead,
            this,&MainWindow::onReadMessage);
}

void MainWindow::onsendMessage()
{
    //给客户端回馈一个信息
    QString str="你好,客户端!";
    m_tcpsocket->write (str.toUtf8());

    ui->label->setText("发送数据成功");

}

void MainWindow::onReadMessage()
{
    //有数据可以读时

    //字节数组
    QByteArray bt = m_tcpsocket->readAll();

    ui->label_Read->setText(bt);

}

三.多线程编程

在Qt中进行多线程编程时,通常需要使用锁来保证共享资源的同步访问,防止多个线程同时访问导致数据的不一致性或者竞争条件的发生。Qt提供了QMutex、QMutexLocker、QReadWriteLock等类来实现锁的功能。

QMutex是最基本的锁类,可以使用lock()方法进行锁定,使用unlock()方法进行解锁。QMutexLocker是一个自动解锁类,可以避免因忘记解锁而导致的死锁问题。QReadWriteLock提供了读写锁的功能,可以允许多个线程同时读取数据,但只允许一个线程写数据。

以下是一个使用QMutex进行多线程编程的示例:

cpp 复制代码
#include <QThread>
#include <QMutex>
#include <QDebug>

class Worker : public QThread
{
public:
    void run() override
    {
        mutex.lock();
        qDebug() << "Thread ID:" << currentThreadId() << " is working...";
        mutex.unlock();
    }

private:
    QMutex mutex;
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    Worker worker1;
    Worker worker2;

    worker1.start();
    worker2.start();

    worker1.wait();
    worker2.wait();

    return app.exec();
}
相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
MrSYJ5 天前
TCP协议理解
后端·tcp/ip
小bo波9 天前
使用Thread子类创建线程 VS 使用Runnable接口创建线程的区别
java·多线程·thread·并发编程·runnable
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt