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等)。

发送端

#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);

}

接收端

#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可用于读取客户端发来的数据报,亦可发送数据报。

客户端

#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();
}

服务端

#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进行多线程编程的示例:

#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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值