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

C++實(shí)現(xiàn)TCP客戶端及服務(wù)器Recv數(shù)據(jù)篩選處理詳解

 更新時(shí)間:2022年10月09日 16:15:26   作者:中國(guó)好公民st  
這篇文章主要為大家介紹了C++實(shí)現(xiàn)TCP客戶端及服務(wù)器Recv數(shù)據(jù)篩選處理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

對(duì)于一個(gè)簡(jiǎn)單的tcp通訊這里我就不再講述了,今天主要為大家講解下,如何從::recv中篩選出一個(gè)完整包邏輯。

就簡(jiǎn)單的以客戶端為例(服務(wù)器接收方也是同樣的邏輯),假設(shè)服務(wù)器一直在頻繁發(fā)送數(shù)據(jù),在recv函數(shù)中并不能保證每次接收的都是一個(gè)完整的包,當(dāng)設(shè)置recv的緩沖區(qū)過(guò)大時(shí),就會(huì)出現(xiàn)多個(gè)包同時(shí)接收的問(wèn)題。

對(duì)于這種情況,初出茅廬的我們有時(shí)會(huì)想不到居然還有多個(gè)包共同出現(xiàn)的問(wèn)題,甚至有些還沒(méi)學(xué)會(huì)如何高效的分離出一個(gè)有效的數(shù)據(jù)包。

一般在進(jìn)行tcp通訊協(xié)議時(shí),為了各個(gè)指令的區(qū)分,通常都會(huì)用以下方式進(jìn)行發(fā)送,如下圖:

具體的通信協(xié)議規(guī)格可以按照各個(gè)業(yè)務(wù)需求來(lái)定義,這里只是列舉了一個(gè)簡(jiǎn)單的例子。

在這篇文章中根據(jù)上圖中的協(xié)議格式,進(jìn)行舉例講解。

協(xié)議標(biāo)識(shí)測(cè)試具體
系統(tǒng)標(biāo)識(shí)0x5A
源設(shè)備標(biāo)識(shí)0xFCFB
預(yù)留字節(jié)假設(shè)占10個(gè)字節(jié)
源設(shè)備編碼根據(jù)連接的服務(wù)端設(shè)備編碼,假設(shè)這是是0x01(編號(hào)1)
命令字具體的業(yè)務(wù)指令,兩個(gè)字節(jié)
數(shù)據(jù)長(zhǎng)度需要發(fā)送的數(shù)據(jù)長(zhǎng)度
數(shù)據(jù)內(nèi)容具體業(yè)務(wù)具體內(nèi)容
校驗(yàn)碼0xEF

在進(jìn)行tcp通訊時(shí),我們每條指令都是按照這種方式進(jìn)行發(fā)送的,接下來(lái),到了文章的重點(diǎn)部分了,該如何對(duì)接收的數(shù)據(jù)篩選?

根據(jù)流程圖可以發(fā)現(xiàn),當(dāng)數(shù)據(jù)不匹配時(shí),需要重新進(jìn)行篩選,程序采用了遞歸的方式進(jìn)行數(shù)據(jù)剔除。這里只是展示了內(nèi)部的流程處理,外部調(diào)用該如何呢?

int nTotalSize = 0;
while(this->JudgeValidData(vetRecvData, nTotalSize) == ture)
{
    //接收到了完整包,對(duì)包進(jìn)行處理
}

代碼解析

nTotalSize:代表了一個(gè)完整數(shù)據(jù)包的總長(zhǎng)度。

vetRecvData:recv函數(shù)接收的所有緩沖區(qū)內(nèi)容。

其實(shí)上面流程圖的內(nèi)容就是JudgeValidData()的函數(shù)處理邏輯。

對(duì)于該函數(shù)的詳細(xì)解析:

1:當(dāng)Tcp緩沖區(qū)的數(shù)據(jù)小于3個(gè)字節(jié)時(shí),不進(jìn)行判斷

此時(shí)字節(jié)數(shù)據(jù)過(guò)小,無(wú)法判斷是不是當(dāng)前程序中需要的

2:判斷包頭是不是一致?

上述表格中,舉例說(shuō)明了包頭的定義,分別是:0x5A、0xFC、0xFB

那么,我們?cè)谂袛鄶?shù)據(jù)時(shí)首先要判斷包頭是否正確?包頭不正確后續(xù)也就不需要判斷了!

char ch0 = vetRecvData[0]; //系統(tǒng)標(biāo)識(shí)
char ch1 = vetRecvData[1]; //標(biāo)識(shí)1
char ch2 = vetRecvData[2]; //標(biāo)識(shí)2
if((ch0 == 0x5A) && (ch1 == 0xFC) && (ch2 == 0xFB))
{
    //包頭正確,進(jìn)行后續(xù)處理
}
else
{
    //包頭不正確,剔除數(shù)據(jù),默認(rèn)剔除緩沖區(qū)的第一個(gè)字節(jié)數(shù)據(jù)
    std::vector<char>::iterator itbegin = vetRecvData.begin();
    vetRecvData.erase(itbegin);
    //重新調(diào)用當(dāng)前函數(shù),遞歸判斷
    return JudgeValidData(vetRecvData, nTotalSize);
}

3:包頭匹配后,判斷是否達(dá)到了數(shù)據(jù)包的固定協(xié)議長(zhǎng)度?

在這里說(shuō)的固定協(xié)議長(zhǎng)度,就是數(shù)據(jù)內(nèi)容之前的字節(jié),在這篇文章中,數(shù)據(jù)內(nèi)容之前有19個(gè)字節(jié),所以,當(dāng)vetRecvData的數(shù)據(jù)總長(zhǎng)度 < 19個(gè)字節(jié)時(shí),不需要處理。

當(dāng)達(dá)到固定協(xié)議長(zhǎng)度后,說(shuō)明該緩沖區(qū)中存在了有效數(shù)據(jù),那么就需要判斷實(shí)際的數(shù)據(jù)內(nèi)容是否達(dá)到了整包的標(biāo)準(zhǔn)?

4:判斷有效數(shù)據(jù)是否接收完整?

首先,需要獲取當(dāng)前包需要接收的數(shù)據(jù)長(zhǎng)度。在這里是占用三個(gè)字節(jié),分別是:16、17、18這三位

int ndatalen = (unsigned char)pThreadParam->vetRecvData[16] * 256 *256+ (unsigned char)pThreadParam->vetRecvData[17]*256 + (unsigned char)pThreadParam->vetRecvData[18];
nTotalSize = 19 + ndatalen + 1;

如果當(dāng)前vetRecvData緩沖區(qū)的數(shù)據(jù) < nTotalSize,說(shuō)明數(shù)據(jù)不完整,不判斷;反之,緩沖區(qū)中存在完整的數(shù)據(jù)。

5:數(shù)據(jù)校驗(yàn)位判斷

最后,判斷下緩沖區(qū)完整包的最后一位是否是校驗(yàn)位?

這樣,才算是一個(gè)完整的一條數(shù)據(jù)包!

到這里,就算判斷完成了,由此可以從一個(gè)大的緩沖區(qū)中抽取出有用的一組數(shù)據(jù)。

內(nèi)部的判斷邏輯講解完之后,接下來(lái)就是外部數(shù)據(jù)使用了。繼續(xù)上面的這段代碼繼續(xù)講解~

int nTotalSize = 0;
while(this->JudgeValidData(vetRecvData, nTotalSize) == ture)
{
    //接收到了完整包,對(duì)包進(jìn)行處理
}

接收到一個(gè)完整包之后,數(shù)據(jù)處理過(guò)程

1:根據(jù)nTotalSize大小從緩沖區(qū)中獲取有效內(nèi)容

2:截取出剩余的緩沖區(qū)內(nèi)容,重新賦值

3:對(duì)一個(gè)完整包數(shù)據(jù)進(jìn)行業(yè)務(wù)處理

將流程轉(zhuǎn)換成代碼,如下:

int nTotalSize = 0;
while (this->JudgeValidData(vetRecvData, nTotalSize) == true)
{
	//這一條數(shù)據(jù)被處理之后,使用一個(gè)臨時(shí)容器存儲(chǔ) 處理的 通訊數(shù)據(jù)
	std::vector<char> vetValidData;
	char* chUseData = new char[nTotalSize];
	memset(chUseData, 0, nTotalSize);
	for (int i = 0; i < vetRecvData.size(); i++)
	{
		if (i < nTotalSize)
		{
			chUseData[i] = vetRecvData[i];
		}
		else
			vetValidData.push_back(vetRecvData[i]);
	}
	//刪除 存儲(chǔ)所有接收字節(jié)的容器 中的數(shù)據(jù)
	vetRecvData.clear();
	vetRecvData = vetValidData; //重新更新數(shù)據(jù)信息
	//接收的是整包數(shù)據(jù)時(shí),進(jìn)行實(shí)際的數(shù)據(jù)處理
	ProcessingPancelValidData(chUseData, nTotalSize);
	delete[] chUseData;
	chUseData = nullptr;
}

以上就是C++實(shí)現(xiàn)TCP客戶端及服務(wù)器Recv數(shù)據(jù)篩選處理詳解的詳細(xì)內(nèi)容,更多關(guān)于C++ 客戶端 服務(wù)器數(shù)據(jù)篩選的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • c語(yǔ)言根據(jù)用戶輸入的出生年份并計(jì)算出當(dāng)前年齡

    c語(yǔ)言根據(jù)用戶輸入的出生年份并計(jì)算出當(dāng)前年齡

    這篇文章主要介紹了c語(yǔ)言根據(jù)用戶輸入的出生年份并計(jì)算出當(dāng)前年齡,需要的朋友可以參考下
    2023-03-03
  • C++數(shù)據(jù)序列化方式(自定義結(jié)構(gòu)體的保存和讀取)

    C++數(shù)據(jù)序列化方式(自定義結(jié)構(gòu)體的保存和讀取)

    這篇文章主要介紹了C++數(shù)據(jù)序列化方式(自定義結(jié)構(gòu)體的保存和讀取),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C語(yǔ)言中大小寫(xiě)字母相互轉(zhuǎn)化的方法示例

    C語(yǔ)言中大小寫(xiě)字母相互轉(zhuǎn)化的方法示例

    在C語(yǔ)言中,大小寫(xiě)字母的轉(zhuǎn)換可以通過(guò)標(biāo)準(zhǔn)庫(kù)中的ctype.h頭文件提供的函數(shù)來(lái)實(shí)現(xiàn),具體來(lái)說(shuō),toupper()函數(shù)可以將小寫(xiě)字母轉(zhuǎn)換為大寫(xiě)字母,而tolower()函數(shù)可以將大寫(xiě)字母轉(zhuǎn)換為小寫(xiě)字母,本文給大家介紹了C語(yǔ)言中大小寫(xiě)字母相互轉(zhuǎn)化的方法,需要的朋友可以參考下
    2024-08-08
  • 二叉樹(shù)入門(mén)和刷題詳解

    二叉樹(shù)入門(mén)和刷題詳解

    這篇文章主要介紹了二叉樹(shù)入門(mén)和刷題詳解的相關(guān)資料,需要的朋友可以參考下
    2023-07-07
  • 7種排序算法的實(shí)現(xiàn)示例

    7種排序算法的實(shí)現(xiàn)示例

    這篇文章主要介紹了7種排序算法的實(shí)現(xiàn)示例,需要的朋友可以參考下
    2014-05-05
  • c++ 讀寫(xiě)yaml配置文件

    c++ 讀寫(xiě)yaml配置文件

    YAML所表示的YAML Ain’t Markup Language,YAML 是一種簡(jiǎn)潔的非標(biāo)記語(yǔ)言,這篇文章主要介紹了在C語(yǔ)言開(kāi)發(fā)中如何讀寫(xiě)配置yaml配置文件,感興趣的同學(xué)可以參考一下
    2023-04-04
  • C語(yǔ)言棧與隊(duì)列面試題詳解

    C語(yǔ)言棧與隊(duì)列面試題詳解

    棧和隊(duì)列,嚴(yán)格意義上來(lái)說(shuō),也屬于線性表,因?yàn)樗鼈円捕加糜诖鎯?chǔ)邏輯關(guān)系為 "一對(duì)一" 的數(shù)據(jù),但由于它們比較特殊,因此將其單獨(dú)作為一章,做重點(diǎn)講解
    2022-04-04
  • 詳解C語(yǔ)言中的getgrgid()函數(shù)和getgrnam()函數(shù)

    詳解C語(yǔ)言中的getgrgid()函數(shù)和getgrnam()函數(shù)

    這篇文章主要介紹了詳解C語(yǔ)言中的getgrgid()函數(shù)和getgrnam()函數(shù),是C語(yǔ)言入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-08-08
  • Qt自定義表頭實(shí)現(xiàn)過(guò)濾功能的方法

    Qt自定義表頭實(shí)現(xiàn)過(guò)濾功能的方法

    這篇文章主要個(gè)給大家介紹了關(guān)于Qt自定義表頭實(shí)現(xiàn)過(guò)濾功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Qt具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • C語(yǔ)言深入講解內(nèi)存操作問(wèn)題

    C語(yǔ)言深入講解內(nèi)存操作問(wèn)題

    程序運(yùn)行的目的是為了得到特定的結(jié)果,計(jì)算機(jī)本質(zhì)上是用于計(jì)算的,既然是用于計(jì)算,就需要參與計(jì)算的數(shù)據(jù),那這些數(shù)據(jù)就存儲(chǔ)在內(nèi)存中,計(jì)算之前參與運(yùn)算的數(shù)據(jù)以及運(yùn)算之后得到的數(shù)據(jù),都存儲(chǔ)在內(nèi)存中,所以對(duì)內(nèi)存操作的掌握就尤為重要,下面我們一起來(lái)看看
    2022-04-04

最新評(píng)論