欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于QT的TCP通信服務(wù)的實(shí)現(xiàn)

 更新時(shí)間:2022年05月09日 09:06:33   作者:MangataTS  
在項(xiàng)目開發(fā)過程中,很多地方都會(huì)用到TCP通信,本文主要介紹了基于QT的TCP通信服務(wù)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、結(jié)構(gòu)

1.1 套接字

應(yīng)用層通過傳輸層進(jìn)行數(shù)據(jù)通信時(shí),TCP和UDP會(huì)遇到同時(shí)為多個(gè)應(yīng)用程序進(jìn)程提供并發(fā)服務(wù)的問題。多個(gè)TCP連接或多個(gè)應(yīng)用程序進(jìn)程可能需要 通過同一個(gè)TCP協(xié)議端口傳輸數(shù)據(jù)。為了區(qū)別不同的應(yīng)用程序進(jìn)程和連接,許多計(jì)算機(jī)操作系統(tǒng)為應(yīng)用程序與TCP/IP協(xié)議交互提供了稱為套接字 (Socket)的接口,區(qū)分不同應(yīng)用程序進(jìn)程間的網(wǎng)絡(luò)通信和連接。

實(shí)際上套接字做的事情就是為我們通信的兩端做一個(gè)連接

1.2 socket通信流程

對(duì)于TCP而言,socket通信的流程大概如下:

tcp通信

1.3 QTcpsocket

對(duì)于客戶端我們就使用的這個(gè)QTcpsocket類去請(qǐng)求服務(wù)器端,我們先看官方給的文檔可以知道:

在這里插入圖片描述

使用該類需要#include <QTcpSocket>頭文件,并且該類是繼承QAbstractSocket類的,而且我們發(fā)現(xiàn)對(duì)于這個(gè)類沒有新增很多的函數(shù),那么我們就應(yīng)該去看它的父類,果不其然,父類中有很多的函數(shù),我們后面進(jìn)行TCP通信其實(shí)也主要是用到父類的一些函數(shù),所以看一下文檔還是有必要的,對(duì)于每一個(gè)函數(shù),你都能點(diǎn)進(jìn)去看參數(shù)、以及描述

在這里插入圖片描述

雖然QAbstractSocket有這么多的函數(shù),但是我們實(shí)際上使用的函數(shù)就那么幾個(gè),我們后面一一介紹,我們現(xiàn)在先來說說QT客戶端創(chuàng)建網(wǎng)絡(luò)連接的流程:

1.我們需要new一個(gè)QTcpSocket的對(duì)象,當(dāng)然初始化只需要將當(dāng)前的obj傳入即可,也就是this,然后給這個(gè)對(duì)象的readyRead創(chuàng)建一個(gè)凹槽做一些收到信號(hào)后的處理(比如將收到的數(shù)據(jù)顯示在某個(gè)地方)。

2.通過connectToHost函數(shù)去連接服務(wù)器,函數(shù)中傳入ipportip要強(qiáng)轉(zhuǎn)為QHostAddress類)

3.通過調(diào)用waitForConnected函數(shù),來判斷服務(wù)器是否連接超時(shí),一般設(shè)置1000,表示的是1s未連接就超時(shí),通過官方的文檔我們能知道如果返回的是true表示的是建立了連接,否則表示建立失敗或未建立連接
注意的是這里,只有使用waitForConnected()后,QTcpSocket才真正嘗試連接服務(wù)器,并返回是否連接的結(jié)果。

4.當(dāng)我們的客戶端接收到readyRead的信號(hào),我們就可以通過readAll()函數(shù)讀取服務(wù)器返回的信息,同樣的我們也可以通過write()函數(shù)向服務(wù)器發(fā)送信息
注意的是這里服務(wù)端讀到的數(shù)據(jù)是一個(gè)QByteArray類型的,我們寫入的數(shù)據(jù)可以Qstring類型的,當(dāng)然也可以是QByteArray

那么這就是客戶端的通信流程了

1.4 QTcpServer

對(duì)于服務(wù)器端我們需要用到QTcpServer類,同樣在官網(wǎng)的文檔我們能得到這個(gè)類的一些基本信息:

在這里插入圖片描述

服務(wù)端的流程:

1.首先創(chuàng)建一個(gè)QTcpServer類,并初始化,然后給這個(gè)對(duì)象的 QTcpServer::newConnection() 建立一個(gè)凹槽,用于處理與客戶端建立連接后要做的一些事情,例如繼續(xù)為QTcpSocket::readyRead創(chuàng)建一個(gè)凹槽進(jìn)行數(shù)據(jù)讀取操作、為QTcpSocket::disconnected創(chuàng)建凹槽用于對(duì)服務(wù)端失聯(lián)后的操作……

2.通過listen(QHostAddress::Any,port)函數(shù)監(jiān)聽所有的ip請(qǐng)求

3.當(dāng)有新的客戶端連接服務(wù)器的時(shí)候,會(huì)自動(dòng)觸發(fā)newConnection()信號(hào)函數(shù),然后我們可以通過通過QTcpSocket * nextPendingConnection()成員函數(shù)來獲取當(dāng)前連接上的新的客戶端類.然后再對(duì)QTcpSocket來進(jìn)行信號(hào)槽綁定(這里可以寫一個(gè)客戶端的池但是我這里為了方便就只寫了一個(gè)客戶端連接的情況)

4.對(duì)于數(shù)據(jù)的讀取的話,由于我們這里只寫了一個(gè)客戶端的情況,那么就可以直接給這個(gè)QTcpSocket對(duì)象綁定和客戶端相同的事件就好

二、設(shè)計(jì)UI

我們直接使用QT Creator自帶的繪制工具,簡單繪制一下就好,界面不重要,重要是控件的objectName 經(jīng)量設(shè)置合理一點(diǎn),下面是我的設(shè)置:

2.1 客戶端UI

在這里插入圖片描述

2.2 服務(wù)器端UI

在這里插入圖片描述

三、核心代碼

對(duì)于客戶端來說:mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpSocket>
#include <QLabel>
#include <QHostAddress>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    setWindowTitle(QString("客戶端"));
    ui->setupUi(this);
    ui->port_2->setText("8899");
    ui->ip->setText("127.0.0.1");
    //剛開始 客戶端的 [斷開服務(wù)] 按鈕不可用
    ui->disconnect->setDisabled(true);
    //創(chuàng)建一個(gè)監(jiān)聽器服務(wù)對(duì)象
    //Tcpserver
    m_tcp=new QTcpSocket(this);

    //客戶端 被動(dòng)的接收服務(wù)器信號(hào)
    connect(m_tcp,&QTcpSocket::readyRead,this,[=](){
        QByteArray array=m_tcp->readAll();
        ui->record->append("服務(wù)端說:"+array);
    });
    //客戶端   斷開
    connect(m_tcp,&QTcpSocket::disconnected,this,[=](){
        m_status->setPixmap(QPixmap(":/a/tmp/disconnect.png").scaled(20,20));
        ui->record->append("斷開鏈接服務(wù)器");
        ui->connect->setDisabled(false);
        ui->disconnect->setDisabled(true);
    });
    //操作狀態(tài)欄圖標(biāo)
    connect(m_tcp,&QTcpSocket::connected,this,[=](){
        m_status->setPixmap(QPixmap(":/a/tmp/connect.png").scaled(20,20));
        ui->record->append("已經(jīng)鏈接成功服務(wù)器");

        //操作按鈕互斥,鏈接成功了,自然鏈接按鈕不能用只有斷開按鈕可以用
        ui->connect->setDisabled(true);
        ui->disconnect->setDisabled(false);
    });
    //增加一點(diǎn)動(dòng)畫效果   狀態(tài)欄的顏色變化
   m_status =new QLabel;
   //狀態(tài)欄的圖片添加
   ui->statusbar->addWidget(new QLabel("鏈接狀態(tài):"));
   ui->statusbar->addWidget(m_status);
   //裝到菜單狀態(tài)欄


}

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

//點(diǎn)擊監(jiān)聽服務(wù),自然而然去啟動(dòng)監(jiān)聽服務(wù)


void MainWindow::on_send_clicked()
{
    //把發(fā)出信息框的數(shù)據(jù)拿到,通過socket套接字發(fā)送出去
    QString string=ui->sendmsg->toPlainText();
    m_tcp->write(string.toUtf8());
    ui->record->append("客戶端說:"+string);
    ui->sendmsg->clear();
}

void MainWindow::on_connect_clicked()
{
    //獲取 IP 端口   才能鏈接
   QString  ip=ui->ip->text();
   unsigned  short port=ui->port_2->text().toUShort();
   qDebug("click_on_connect state = %d\n",m_tcp->state());
   m_tcp->connectToHost(QHostAddress(ip),port);
   if(m_tcp->waitForConnected(1000)) {
        qDebug("connected !\n");
        ui->record->clear();
   }
   else
       qDebug("connect out time limit !\n");

}

void MainWindow::on_disconnect_clicked()
{
    qDebug("loc1 state = %d\n",m_tcp->state());
    m_tcp->disconnectFromHost();
    qDebug("loc2 state = %d\n",m_tcp->state());
    if(m_tcp->state() == QAbstractSocket::UnconnectedState
            || m_tcp->waitForDisconnected(1000))
        qDebug("Disconnected!\n");
    else
        qDebug("Disconnect fail!\n");
    m_tcp->close();
    ui->connect->setDisabled(false);
    ui->disconnect->setDisabled(false);
}

對(duì)于服務(wù)器來說:mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QLabel>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->port_2->setText("8899");
    //創(chuàng)建一個(gè)監(jiān)聽器服務(wù)對(duì)象
    //Tcpserver
    m_s=new QTcpServer(this);
    m_tcp = new QTcpSocket;
    //啟動(dòng)監(jiān)聽   通過點(diǎn)擊監(jiān)聽按鈕實(shí)現(xiàn),并且在按鈕轉(zhuǎn)到的槽函數(shù)實(shí)現(xiàn)監(jiān)聽
    //上述完成監(jiān)聽,就等待用戶/客戶端的鏈接
    connect(m_s,&QTcpServer::newConnection,this,[=](){
        //狀態(tài)欄變色
        m_status->setPixmap(QPixmap(":/a/tmp/connect.png").scaled(20,20));
        //程序到此步驟證明有用戶鏈接,啟用socket通信傳輸并解析數(shù)據(jù)
        //實(shí)例此次通信對(duì)象  nextPendingConnection得到一個(gè)可供通信的套接字對(duì)象
        m_tcp=m_s->nextPendingConnection();
        QString client_ip = m_tcp->peerAddress().toString().split("::ffff:")[1];
        quint16 client_port = m_tcp->peerPort();

        ui->record->append(tr("%1:%2 connected!\n").arg(client_ip).arg(client_port));
        //進(jìn)行對(duì)象處理,檢測(cè)傳輸?shù)臄?shù)據(jù),利用connect對(duì)tcp套接字操作
        connect(m_tcp,&QTcpSocket::readyRead,this,[=](){
                QByteArray array = m_tcp->readAll();
                ui->record->append("客戶端說:"+array);
        });

        //客戶端斷開操作
        connect(m_tcp,&QTcpSocket::disconnected,this,[=](){
            QString client_ip = m_tcp->peerAddress().toString().split("::ffff:")[1];
            quint16 client_port = m_tcp->peerPort();

            ui->record->append(tr("%1:%2 Disconnected!\n").arg(client_ip).arg(client_port));
            m_tcp->disconnectFromHost();
            if(m_tcp->state() == QAbstractSocket::UnconnectedState
                    || m_tcp->waitForDisconnected(1000))
                qDebug("Disconnected!\n");
            else
                qDebug("Disconnect fail!\n");
            m_status->setPixmap(QPixmap(":/a/tmp/disconnect.png").scaled(20,20));
        });
    });
    //增加一點(diǎn)動(dòng)畫效果   狀態(tài)欄的顏色變化
   m_status =new QLabel;
   //狀態(tài)欄的圖片添加
   //m_status->setPixmap(QPixmap(":/a/tmp/connect.png").scaled(20,20));
   ui->statusbar->addWidget(new QLabel("鏈接狀態(tài):"));
   ui->statusbar->addWidget(m_status);
   //裝到菜單狀態(tài)欄
}

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

//點(diǎn)擊監(jiān)聽服務(wù),自然而然去啟動(dòng)監(jiān)聽服務(wù)
void MainWindow::on_setlisten_clicked()
{  setWindowTitle("服務(wù)器");
    //得到窗口 lineedit窗口的端口號(hào)
    unsigned  short  port=ui->port_2->text().toShort();
    //進(jìn)行監(jiān)聽   ip   端口
    m_s->listen(QHostAddress::Any,port);
    ui->setlisten->setDisabled(true);
}

void MainWindow::on_send_clicked()
{
    //把發(fā)出信息框的數(shù)據(jù)拿到,通過socket套接字發(fā)送出去
    QString string=ui->sendmsg->toPlainText();
    m_tcp->write(string.toUtf8());
    ui->record->append("服務(wù)端說:"+string);
    ui->sendmsg->clear();
}

四、效果圖

在這里插入圖片描述

在這里插入圖片描述

 到此這篇關(guān)于基于QT的TCP通信服務(wù)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)QT TCP通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論