国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

網(wǎng)絡(luò)通信/QTcpSocket/實(shí)現(xiàn)一個(gè)可在子線程中發(fā)送和接收數(shù)據(jù)的TCP客戶端

這篇具有很好參考價(jià)值的文章主要介紹了網(wǎng)絡(luò)通信/QTcpSocket/實(shí)現(xiàn)一個(gè)可在子線程中發(fā)送和接收數(shù)據(jù)的TCP客戶端。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

概述

近來(lái)一直接使用WinSocket做網(wǎng)絡(luò)編程,有很長(zhǎng)一段時(shí)間不再使用Qt框架下的相關(guān)網(wǎng)路通信類。有不少之前積壓的問(wèn)題直到現(xiàn)在也沒(méi)怎么弄清楚,在CSDN中亂七八糟的存了好幾篇草稿,亟待整理。最近要寫(xiě)一個(gè)簡(jiǎn)單地相機(jī)升級(jí)程序,于是重操舊業(yè)。

歷史

網(wǎng)絡(luò)通信中,尤其是在收發(fā)工作較為耗時(shí)或交互頻率較高的時(shí)候,為了使得通信過(guò)程不造成UI的卡頓現(xiàn)象,一般要求通信工作在次線程(子線程)中完成。在Windows編程中,我們可以使用Select模式等實(shí)現(xiàn)這一需求。在Qt網(wǎng)絡(luò)編程框架下,也做過(guò)些嘗試。如 《網(wǎng)絡(luò)通信/QTcpSocket/QObject:Cannot create children for a parent that is in a different thread.》 文章中提到的方案(臨時(shí)記為PlanA),它將Qt套接字對(duì)象移動(dòng)到次線程,并在主線程中直接調(diào)用套接字接口,此時(shí)存在 “以其他線程對(duì)象為父對(duì)象,在本線程創(chuàng)建子對(duì)象” 的告警。
草稿中還記錄了另一個(gè)方案(臨時(shí)記為PlanB)
如常見(jiàn)的Qt多線程編程,定義一個(gè)workker類對(duì)象,將其移動(dòng)到次線程中,由其全權(quán)負(fù)責(zé)對(duì)m_socket套接字對(duì)象的操作,包括使用套接字進(jìn)行連接、斷開(kāi)、數(shù)據(jù)發(fā)送等操作。此方案依然存在PlanA中的問(wèn)題,因?yàn)榇藭r(shí)套接字對(duì)象沒(méi)有進(jìn)行過(guò)moveToThread操作,其還是歸屬于創(chuàng)建它的主線程,但相關(guān)函數(shù)調(diào)用線程卻為wirker所在的次線程。
通過(guò)分析以前的失敗經(jīng)驗(yàn),似乎得出了一個(gè)結(jié)論:
套接字的相關(guān)接口只能在套接字對(duì)象所屬的線程內(nèi)調(diào)用(如果套接字對(duì)象沒(méi)有執(zhí)行過(guò)moveToThread操作,那么套接字對(duì)象的所屬線程就是創(chuàng)建它的線程)。因此,如果想支持在次線程中執(zhí)行連接/斷開(kāi)服務(wù)、數(shù)據(jù)收/發(fā)過(guò)程,則必須的要將套接字對(duì)象本身進(jìn)行moveToThread操作,且要將其他線程對(duì)該對(duì)象的操作轉(zhuǎn)換到moveToThread后的線程內(nèi)。

一種可行的實(shí)現(xiàn)

如下方案實(shí)現(xiàn)了,發(fā)送和接收操作同時(shí)運(yùn)行在一個(gè)次線程內(nèi)。其實(shí)通常情況下的交互過(guò)程,不會(huì)在同一時(shí)間段內(nèi)雙向高速通信,在一個(gè)時(shí)間段內(nèi)一般只有一方在高速發(fā)送數(shù)據(jù),或者多設(shè)備發(fā)送然后由集中控制設(shè)備接收處理。因此像WinSocket編程Select模式下實(shí)現(xiàn)在一個(gè)線程內(nèi)執(zhí)行收發(fā)操作,是很常見(jiàn)的方案。需要注意的是,速率要求更高的場(chǎng)景,從本質(zhì)就不適合使用Qt的網(wǎng)絡(luò)通信封裝。

//.h

#pragma once

#include <QTcpSocket>

//該對(duì)象最終運(yùn)行在次線程中
class TcpClient : public QTcpSocket
{
    Q_OBJECT
public:
    TcpClient(QObject *parent = NULL);
    ~TcpClient();
public:
    //
    void ClientConnectToHost(const QString &address, quint16 port);
    //
    void ClientSendingData(const QByteArray &c_btaData);
    //
    bool IsOnline();
signals:
    //轉(zhuǎn)換來(lái)自主線程的鏈接操作
    void SignalConnectToHost(const QString & address, quint16 port);
signals:
    //轉(zhuǎn)換來(lái)自主線程的發(fā)送操作
    void SignalSendingData(const QByteArray c_btaData);
signals:
    //在次線程中緩沖并滑動(dòng)解析TCP流后/按約定格式再發(fā)布
    void SignalPublishFormatRecvData(const QString c_btaData);
private:
    //標(biāo)記連接情況
    bool m_bOnLine = false;
    //緩沖收到的流數(shù)據(jù)
    QByteArray m_btaReceiveFromService;
};

//.cpp

#include <QThread>
#include <QDebug>
#include <QHostAddress>
#include "tcp_client.h"

TcpClient::TcpClient(QObject *parent)
    : QTcpSocket(parent)
{
    //自動(dòng)連接在信號(hào)發(fā)射時(shí)被識(shí)別為隊(duì)列連接/信號(hào)在主線程發(fā)射
    connect(this, &TcpClient::SignalConnectToHost, this, [&](const QString & address, quint16 port) {
        //test record# in child thread id 20588
        qDebug("SlotConnectToHost ThreadID:%d", QThread::currentThreadId());
        //
        this->connectToHost(QHostAddress(address), port, QIODevice::ReadWrite);
    }, Qt::AutoConnection);

    //連接了TCP服務(wù)端
    QObject::connect(this, &QAbstractSocket::connected, this, [&]() {
        //test record# in child thread id 20588
        qDebug("SlotHasConnected ThreadID:%d", QThread::currentThreadId());
        //
        m_bOnLine = true;
    }, Qt::DirectConnection);

    //斷開(kāi)了TCP服務(wù)端
    QObject::connect(this, &QAbstractSocket::disconnected, this, [&]() {
        //test record# in child thread id 20588
        qDebug("SlotHasDisconnected ThreadID:%d", QThread::currentThreadId());
        //
        m_bOnLine = false;
    }, Qt::DirectConnection);

    //收到了TCP服務(wù)的數(shù)據(jù)
    QObject::connect(this, &QIODevice::readyRead, this, [&]() {
        //test record# in child thread id 20588
        qDebug("SlotIODeviceReadyRead ThreadID:%d", QThread::currentThreadId());
        //讀取全部數(shù)據(jù)
        m_btaReceiveFromService.append(this->readAll());
        //
        int iFindPos = m_btaReceiveFromService.indexOf("\r\n");
        //檢查分隔符
        while (-1 != iFindPos)
        {
            //分割數(shù)據(jù)流
            QString strPublish = m_btaReceiveFromService.left(iFindPos);
            //發(fā)布解析后的格式數(shù)據(jù)
            emit SignalPublishFormatRecvData(strPublish);
            //
            m_btaReceiveFromService.remove(0, iFindPos + strlen("\r\n"));
            //
            iFindPos = m_btaReceiveFromService.indexOf("\r\n");
        }
    }, Qt::DirectConnection);

    //執(zhí)行數(shù)據(jù)發(fā)送過(guò)程
    QObject::connect(this, &TcpClient::SignalSendingData, this, [&](const QByteArray c_btaData) {
        //test record# in child thread id 20588
        qDebug("SlotSendingData ThreadID:%d", QThread::currentThreadId());
        //
        this->write(c_btaData);
    }, Qt::AutoConnection);
}

//
TcpClient::~TcpClient()
{
}

//跨線程轉(zhuǎn)換
void TcpClient::ClientConnectToHost(const QString & address, quint16 port)
{
    emit SignalConnectToHost(address, port);
}

//跨線程轉(zhuǎn)換
void TcpClient::ClientSendingData(const QByteArray & c_btaData)
{
    emit SignalSendingData(c_btaData);
}

//是否在線
bool TcpClient::IsOnline()
{
    return m_bOnLine;
}

//main /using of my tcp client

UpdateCamera::UpdateCamera(QWidget *parent) : QMainWindow(parent)
{
    //創(chuàng)建TCP客戶端
    m_pmyTcpSocket = new TcpClient();
    //
    m_pThreadSending = new QThread();
    //
    m_pmyTcpSocket->moveToThread(m_pThreadSending);
    //
    m_pThreadSending->start();

    //連接到相機(jī)的TCP服務(wù)
    connect(ui.pushButton_connect, &QPushButton::clicked, [&]() {
    	...
        m_pmyTcpSocket->ClientConnectToHost(strIPUsing, SER_PORT);
    });
    
    //文件發(fā)送
    connect(ui.pushButton_file_sending, &QPushButton::clicked, [&]() {
  		...
        //執(zhí)行客戶端文件發(fā)送過(guò)程
        m_pmyTcpSocket->ClientSendingData(DataOfBin);
    });

    //接收服務(wù)端發(fā)送的數(shù)據(jù) /從子線程到主線程的隊(duì)列連接
    connect(m_pTcpClient, &TcpClient::SignalPublishFormatRecvData, this, [&](const QString c_btaData) {
        ui.textEdit->append(c_btaData);
        ui.textEdit->moveCursor(QTextCursor::End);
        if (ui.textEdit->toPlainText().size() > 2 * 1024 * 1024)
            ui.textEdit->clear();
    }, Qt::AutoConnection);
}

一些總結(jié)

在實(shí)現(xiàn)和測(cè)試上述TCP客戶端的過(guò)程中,也驗(yàn)證和消除了一些 “老問(wèn)題”。
1、由QIODevice::readyRead信號(hào)的DirectConnection連接的lambda槽函數(shù)執(zhí)行結(jié)果,可得出:如果一個(gè)Tcp對(duì)象被歸屬到了子線程X中,那么readyRead信號(hào)最終將從此子線程X發(fā)出。
2.、同上,connected信號(hào)、disconnected信號(hào)等其發(fā)射線程,都是套接字對(duì)象的所在線程。

其他需要注意的是:
1、當(dāng)connect內(nèi)部使用lambda表達(dá)式做槽函數(shù)時(shí),注意選擇有Qt::ConnectionType 參數(shù)的那個(gè)函數(shù)版本,否則將默認(rèn)為直接連接。

//默認(rèn)為直接連接
connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
//可以配置連接方式 //Qt::UniqueConnections do not work for lambdas
connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)

2、默認(rèn)的連接方式 Qt::AutoConnection 在connect后生效的時(shí)刻是emit發(fā)射的時(shí)候,而不是執(zhí)行connect 語(yǔ)句的時(shí)候。因此先執(zhí)行moveToThread還是先執(zhí)行connect過(guò)程是無(wú)關(guān)緊要的。具體可參見(jiàn)幫助文檔中提及的:If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
3、至此,還沒(méi)有讀過(guò)Qt網(wǎng)絡(luò)通信框架的源碼,因此對(duì)于如下問(wèn)題,還是無(wú)法清晰理解,如:Qt是如何對(duì)WinSocket進(jìn)行封裝的,Qt網(wǎng)絡(luò)通信采用了哪種IO模型,QIODevice的架構(gòu)是怎樣的,readyRead信號(hào)是在什么情景下發(fā)出的,QThread線程是如何對(duì)接QIODevice上的?同一個(gè)Qt套接字對(duì)象到底能否在兩個(gè)不同的子線程中進(jìn)行工作?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-479975.html

到了這里,關(guān)于網(wǎng)絡(luò)通信/QTcpSocket/實(shí)現(xiàn)一個(gè)可在子線程中發(fā)送和接收數(shù)據(jù)的TCP客戶端的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux網(wǎng)絡(luò)編程:socket & pthread_create()多線程 實(shí)現(xiàn)clients/server通信

    Linux網(wǎng)絡(luò)編程:socket & pthread_create()多線程 實(shí)現(xiàn)clients/server通信

    UNIX網(wǎng)絡(luò)編程:socket fork()多進(jìn)程 實(shí)現(xiàn)clients/server通信 隨筆介紹了通過(guò)fork()多進(jìn)程實(shí)現(xiàn)了服務(wù)器與多客戶端通信。但除了多進(jìn)程能實(shí)現(xiàn)之外,多線程也是一種實(shí)現(xiàn)方式。 重要的是,多進(jìn)程和多線程是涉及操作系統(tǒng)層次。隨筆不僅要利用pthread_create()實(shí)現(xiàn)多線程編程,也要理解線

    2024年02月05日
    瀏覽(23)
  • 網(wǎng)絡(luò)通信(13)-C#TCP服務(wù)器和客戶端同時(shí)在一個(gè)進(jìn)程實(shí)現(xiàn)的實(shí)例

    網(wǎng)絡(luò)通信(13)-C#TCP服務(wù)器和客戶端同時(shí)在一個(gè)進(jìn)程實(shí)現(xiàn)的實(shí)例

    有時(shí)項(xiàng)目需求中需要服務(wù)器和客戶端同時(shí)在一個(gè)進(jìn)程實(shí)現(xiàn),一邊需要現(xiàn)場(chǎng)接收多個(gè)客戶端的數(shù)據(jù),一邊需要將數(shù)據(jù)匯總后發(fā)送給遠(yuǎn)程服務(wù)器。下面通過(guò)實(shí)例演示此項(xiàng)需求。 C#TCP服務(wù)器和客戶端同時(shí)在一個(gè)進(jìn)程實(shí)現(xiàn)的實(shí)例如下: 界面設(shè)計(jì) UI文件代碼

    2024年01月22日
    瀏覽(34)
  • unity Sockets通信 使用UDP協(xié)議,設(shè)置客戶端電腦網(wǎng)絡(luò)配置,使用新線程獲取數(shù)據(jù),解決卡頓問(wèn)題,

    unity Sockets通信 使用UDP協(xié)議,設(shè)置客戶端電腦網(wǎng)絡(luò)配置,使用新線程獲取數(shù)據(jù),解決卡頓問(wèn)題,

    今天調(diào)試和服務(wù)器連接,發(fā)現(xiàn)始終獲取不到服務(wù)器的數(shù)據(jù), 電腦和服務(wù)器都在同一局域網(wǎng),仍然獲取不到, 下面是電腦環(huán)境配置, 第一步: 設(shè)置網(wǎng)絡(luò)為專用網(wǎng)絡(luò),然后點(diǎn)擊配置防火墻和安全設(shè)置,關(guān)閉防火墻 (點(diǎn)擊所連接的wifi的屬性) 第二步:設(shè)置出站 入站規(guī)則 點(diǎn)擊高

    2024年02月07日
    瀏覽(28)
  • Qt實(shí)現(xiàn)TCP網(wǎng)絡(luò)通信

    Qt實(shí)現(xiàn)TCP網(wǎng)絡(luò)通信

    在標(biāo)準(zhǔn)C++中沒(méi)有提供專門用于套接字通信的類,所以只能使用操作系統(tǒng)提供的基于C語(yǔ)言的API函數(shù),基于這些C的API函數(shù)我們也可以封裝自己的C++類?;蛘呶覀兛梢允褂肣t框架,它提供了用于套接字通信的類(TCP、UDP)這樣我們就可以直接調(diào)用相關(guān)API即可。 使用Qt提供的類進(jìn)行基于

    2024年04月17日
    瀏覽(23)
  • Unity實(shí)現(xiàn)網(wǎng)絡(luò)通信(UDP)

    Unity實(shí)現(xiàn)網(wǎng)絡(luò)通信(UDP)

    UDP通信特點(diǎn): ? ? ? ? 無(wú)連接,多對(duì)多 ? ? ? ? 不可靠 ? ? ? ? 面向數(shù)據(jù)報(bào) ? ? ? ? 效率高 UDP中的分包與黏包 分包:一段數(shù)據(jù)被分為兩段或多段傳輸,在UDP通信方式中,因?yàn)閁DP的不可靠性無(wú)法保證有序傳輸,因此盡量避免UDP自動(dòng)分包。 ????????其中一種方式是保證消

    2024年02月04日
    瀏覽(17)
  • Linux對(duì)網(wǎng)絡(luò)通信的實(shí)現(xiàn)

    Linux對(duì)網(wǎng)絡(luò)通信的實(shí)現(xiàn)

    1、OP_WRITE觸發(fā)條件:當(dāng)操作系統(tǒng)寫(xiě)緩沖區(qū)有空閑時(shí)就緒。一般情況下寫(xiě)緩沖區(qū)都有空閑空間,小塊數(shù)據(jù)直接寫(xiě)入即可,沒(méi)必要注冊(cè)該操作類型,否則該條件不斷就緒浪費(fèi)cpu;但如果是寫(xiě)密集型的任務(wù),比如文件下載等,緩沖很可能滿,注冊(cè)該操作類型很有必要,同時(shí)注意寫(xiě)完

    2024年02月08日
    瀏覽(20)
  • OpenSSL實(shí)現(xiàn)SSL網(wǎng)絡(luò)通信

    Certainly! Here are the C language programs for a simple OpenSSL client and server that can establish a secure communication channel between them: l inux環(huán)境下 OpenSSL Server Program (server.c): OpenSSL Client Program (client.c): To compile and run the programs, you’ll need to make sure you have the OpenSSL library installed on your system. Use the foll

    2024年02月06日
    瀏覽(21)
  • C++實(shí)現(xiàn)socket網(wǎng)絡(luò)通信

    C++實(shí)現(xiàn)socket網(wǎng)絡(luò)通信

    ??SOCKET網(wǎng)絡(luò)通信系列文章鏈接如下:?? ??【小沐學(xué)python】(一)Python簡(jiǎn)介和安裝?? ??Python實(shí)現(xiàn)socket網(wǎng)絡(luò)通信?? ??C++實(shí)現(xiàn)socket網(wǎng)絡(luò)通信?? ??Android實(shí)現(xiàn)socket網(wǎng)絡(luò)通信?? ??nodejs實(shí)現(xiàn)socket網(wǎng)絡(luò)通信?? 《斗詩(shī)篇》 陳獻(xiàn)章: 窗外竹青青,窗間人獨(dú)坐。 究竟竹與人,原來(lái)無(wú)兩

    2023年04月09日
    瀏覽(20)
  • Java 網(wǎng)絡(luò)編程詳解:實(shí)現(xiàn)網(wǎng)絡(luò)通信的核心技術(shù)

    網(wǎng)絡(luò)編程是指利用計(jì)算機(jī)網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)交換和通信的過(guò)程。它涉及到在不同主機(jī)之間傳輸數(shù)據(jù),并允許不同設(shè)備之間進(jìn)行連接和通信。網(wǎng)絡(luò)編程不僅限于互聯(lián)網(wǎng),也可以包括局域網(wǎng)或廣域網(wǎng)等各種網(wǎng)絡(luò)環(huán)境。 在當(dāng)今的互聯(lián)網(wǎng)時(shí)代,幾乎所有的應(yīng)用都需要在不同設(shè)備之間進(jìn)行數(shù)

    2024年02月11日
    瀏覽(20)
  • 【JavaEE】_基于UDP實(shí)現(xiàn)網(wǎng)絡(luò)通信

    【JavaEE】_基于UDP實(shí)現(xiàn)網(wǎng)絡(luò)通信

    目錄 1. 服務(wù)器 1.1?實(shí)現(xiàn)邏輯 1.2 代碼 1.3 部分代碼解釋 2. 客戶端 2.1?實(shí)現(xiàn)邏輯 2.2 代碼 2.3?客戶端部分代碼解釋 3. 程序運(yùn)行結(jié)果 4. 服務(wù)器客戶端交互邏輯 普通服務(wù)器:收到請(qǐng)求,根據(jù)請(qǐng)求計(jì)算響應(yīng),返回響應(yīng); 回顯服務(wù)器:忽略計(jì)算,直接將收到的請(qǐng)求作為響應(yīng)返回; (

    2024年01月21日
    瀏覽(20)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包