首頁 > 軟體

Qt網路程式設計實現TCP通訊

2022-08-18 18:01:31

Qt網路程式設計實現TCP通訊,供大家參考,具體內容如下

標籤(空格分隔): Tcp通訊

一、Tcp簡介

(1)TCP(Transmission Control Protocol,傳輸控制協定)TCP是一個用於資料傳輸的傳輸層網路協定,多個網路協定包括(HTTP和FTP都是基於TCP協定),TCP是面向資料流和連線的可靠的傳輸協定,它區別於傳輸層的另外一個協定UDP(具體可看—Qt簡單實現UDP通訊) 。

(2)QTcpSocket繼承自QAbstractSocket,與QUdpSocket傳輸的資料包不同的是,QTcpSocket傳輸的是連續的資料流,尤其適合連續的資料傳輸,TCP一般分為使用者端和伺服器端,即C/S (Client/Server模型)。

(3)QTcpSocket代表了兩個獨立的資料流,一個用來讀取資料,一個用來寫入資料,分別採用QTcpSocket::read()及QTcpSocket::write()操作,讀取資料前先呼叫QTcpSocket::bytesAvailable來確定已有足夠的資料可用。QTcpServer處理使用者端的連線,可通過QTcpServer::listen()監聽使用者端發來的連線請求,每當有使用者端連線時會發射newConnection()訊號,QTcpSocket可用於讀取使用者端發來的資料包,亦可傳送資料包。

二、傳輸層兩大協定TcpUdp的異同

三、小demo實現Tcp使用者端伺服器端通訊

1、伺服器端:

新建Qt Widgets Application,用作tcp伺服器端,伺服器端任何時候只能被動等待連線,繼承自Qwidget類即可,設計ui介面,介面如下:

開啟pro檔案,新增支援網路程式設計模組,使用者端也需做如下修改:

新增tcp伺服器端m_tcpServer、tcp伺服器端通訊端m_tcpSocket,在建構函式中監聽使用者端的連線,樣例中伺服器端主要監聽任何任何ip地址上的6666埠,併為使用者端連線時的newConnection訊號新增相應的槽函數。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void onNewConnect();    //使用者端新的連線請求處理
    void onSendBackMsg();   //反饋資訊給使用者端新的連線
    void onReadMsg();       //伺服器端讀取使用者端發來的資料
private:
    Ui::Widget *ui;
    QTcpServer* m_tcpServer;    //tcp伺服器端
    QTcpSocket* m_tcpSocket;    //tcp通訊端
};
#endif // WIDGET_H

當伺服器端收到使用者端的連線時,伺服器端tcp反饋資訊給使用者端,同時使用者端顯示的資料顯示到標籤上:

#include "widget.h"
#include "ui_widget.h"
#include <QTcpSocket>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    m_tcpServer=new QTcpServer(this);
    //伺服器端監聽使用者端發來的請求
    if(!m_tcpServer->listen(QHostAddress::AnyIPv4,6666)){
        qDebug()<<m_tcpServer->errorString();
        close();
    }
    connect(m_tcpServer,&QTcpServer::newConnection,this,&Widget::onNewConnect);
    connect(m_tcpServer,&QTcpServer::newConnection,this,&Widget::onSendBackMsg);
}

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

void Widget::onNewConnect()
{
    //當前連線的使用者端
    m_tcpSocket=m_tcpServer->nextPendingConnection();
    //斷開連線
    connect(m_tcpSocket,&QTcpSocket::disconnected,
            m_tcpSocket,&QTcpSocket::deleteLater);
    //socket有資料時會傳送readyRead訊號
    connect(m_tcpSocket,&QTcpSocket::readyRead,
            this,&Widget::onReadMsg);
}
void Widget::onSendBackMsg()
{
    QString str="你好,使用者端!";
    m_tcpSocket->write(str.toUtf8());
    ui->label->setText("反饋資料成功!");

}

void Widget::onReadMsg()
{
    //伺服器端將使用者端發來的資料顯示到標籤上
    QByteArray bt=m_tcpSocket->readAll();
    ui->readLabel->setText(bt);
}

2、使用者端

與伺服器端一樣,再新建Qt Widgets Application專案,用作tcp使用者端,繼承自Qwidget類即可,設計ui介面,介面如下:

新增使用者端tcp,在pro檔案中新增網路程式設計模組network,給連線、傳送按鈕新增點選訊號。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void onReadMessage();   //處理伺服器端反饋的資料
    void onDisplayError(QAbstractSocket::SocketError e);    //列印錯誤資訊
    void on_connectBtn_clicked();   //點選連線按鈕響應訊號的槽函數
    void on_sendBtn_clicked();  //點選傳送按鈕響應的槽函數
private:
    Ui::Widget *ui;
    QTcpSocket* m_tcpSocket;    //tcp使用者端
};
#endif // WIDGET_H

建構函式中為伺服器端發來資料時觸發的readyRead訊號新增了響應的槽函數onReadMessage,同時設定了使用者端連線時的預設ip地址和埠,onReadMessage槽函數將伺服器端反饋的資料顯示到標籤上,on_sendBtn_clicked槽函數中將行編輯框中的內容傳送給tcp伺服器端。

#include "widget.h"
#include "ui_widget.h"
#include <QAbstractSocket>
const int gTcpPort=6666;
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    m_tcpSocket=new QTcpSocket(this);
    //socket有資料來了,做處理
    connect(m_tcpSocket,&QTcpSocket::readyRead,
            this,&Widget::onReadMessage);
    connect(m_tcpSocket,SIGNAL(QAbstractSocket::SocketError),
            this,SLOT(onDisplayError(QAbstractSocket::SocketError)));
    //設定使用者端連線預設的主機地址及埠號
    ui->hostLineEdit->setText("127.0.0.1");
    ui->portLineEdit->setText(QString::number(gTcpPort));
}

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

void Widget::onReadMessage()
{
    QByteArray bt;
    bt.resize(m_tcpSocket->bytesAvailable());
    m_tcpSocket->read(bt.data(),bt.size());
    //將使用者端反饋的資料顯示到標籤上
    ui->recvLabel->setText(bt);
}

void Widget::onDisplayError(QAbstractSocket::SocketError e)
{
    qDebug()<<"SocketError:"<<e<<endl
           <<m_tcpSocket->errorString();
}

void Widget::on_connectBtn_clicked()
{
    m_tcpSocket->abort();
    //連線伺服器端
    m_tcpSocket->connectToHost(ui->hostLineEdit->text(),
                               ui->portLineEdit->text().toInt());
}

void Widget::on_sendBtn_clicked()
{
    m_tcpSocket->write(ui->sendEdit->text().toUtf8());
    m_tcpSocket->flush();//清空緩衝區
}

四、執行結果

先開啟伺服器端,再執行使用者端

使用者端採用預設ip和埠,這裡的ip地址也可修改為其他,埠必須與伺服器端監聽埠一致,點選連線:

在行編輯框中隨便輸入內容,點選傳送:

ok達到目的!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com