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();
}
相关推荐
仙陨1 小时前
QT实现TCP协议
服务器·网络·qt
加油,旭杏1 小时前
【Linux】网络层协议——IP
linux·服务器·tcp/ip·ip·网络层·网段划分·私有ip和公网ip
shuai_2582 小时前
深入解析C++单例模式:从基础到线程安全的高效实现
开发语言·c++·qt
大柏怎么被偷了3 小时前
【Qt】子控件选择器
开发语言·c++·qt
十五年专注C++开发3 小时前
CTK框架(十):PluginAdmin插件
开发语言·c++·qt·插件开发·ctk
KookeeyLena54 小时前
我想要抓取新加坡当地电商平台数据,使用什么地区的IP最合适
服务器·网络·tcp/ip
Black_Friend4 小时前
Windows10 如何设置电脑ip
网络·网络协议·tcp/ip
做程序员的第一天4 小时前
计算机网络 ---- OSI参考模型&TCP/IP模型
网络·tcp/ip·计算机网络
hgdlip4 小时前
路由器的固定ip地址是啥意思?固定ip地址有什么好处
网络·网络协议·tcp/ip·路由器·固定ip地址
KookeeyLena34 小时前
如何进行IP清洗
服务器·网络·tcp/ip