C++实现TCP客户端及服务器Recv数据筛选处理详解

目录
  • 正文
  • 代码解析
    • 1:当Tcp缓冲区的数据小于3个字节时,不进行判断
    • 2:判断包头是不是一致?
    • 3:包头匹配后,判断是否达到了数据包的固定协议长度?
    • 4:判断有效数据是否接收完整?
    • 5:数据校验位判断

正文

对于一个简单的tcp通讯这里我就不再讲述了,今天主要为大家讲解下,如何从::recv中筛选出一个完整包逻辑。

就简单的以客户端为例(服务器接收方也是同样的逻辑),假设服务器一直在频繁发送数据,在recv函数中并不能保证每次接收的都是一个完整的包,当设置recv的缓冲区过大时,就会出现多个包同时接收的问题。

对于这种情况,初出茅庐的我们有时会想不到居然还有多个包共同出现的问题,甚至有些还没学会如何高效的分离出一个有效的数据包。

一般在进行tcp通讯协议时,为了各个指令的区分,通常都会用以下方式进行发送,如下图:

具体的通信协议规格可以按照各个业务需求来定义,这里只是列举了一个简单的例子。

在这篇文章中根据上图中的协议格式,进行举例讲解。

协议标识 测试具体
系统标识 0x5A
源设备标识 0xFCFB
预留字节 假设占10个字节
源设备编码 根据连接的服务端设备编码,假设这是是0x01(编号1)
命令字 具体的业务指令,两个字节
数据长度 需要发送的数据长度
数据内容 具体业务具体内容
校验码 0xEF

在进行tcp通讯时,我们每条指令都是按照这种方式进行发送的,接下来,到了文章的重点部分了,该如何对接收的数据筛选?

根据流程图可以发现,当数据不匹配时,需要重新进行筛选,程序采用了递归的方式进行数据剔除。这里只是展示了内部的流程处理,外部调用该如何呢?

int nTotalSize = 0;
while(this->JudgeValidData(vetRecvData, nTotalSize) == ture)
{
    //接收到了完整包,对包进行处理
}

代码解析

nTotalSize:代表了一个完整数据包的总长度。

vetRecvData:recv函数接收的所有缓冲区内容。

其实上面流程图的内容就是JudgeValidData()的函数处理逻辑。

对于该函数的详细解析:

1:当Tcp缓冲区的数据小于3个字节时,不进行判断

此时字节数据过小,无法判断是不是当前程序中需要的

2:判断包头是不是一致?

上述表格中,举例说明了包头的定义,分别是:0x5A、0xFC、0xFB

那么,我们在判断数据时首先要判断包头是否正确?包头不正确后续也就不需要判断了!

char ch0 = vetRecvData[0]; //系统标识
char ch1 = vetRecvData[1]; //标识1
char ch2 = vetRecvData[2]; //标识2
if((ch0 == 0x5A) && (ch1 == 0xFC) && (ch2 == 0xFB))
{
    //包头正确,进行后续处理
}
else
{
    //包头不正确,剔除数据,默认剔除缓冲区的第一个字节数据
    std::vector<char>::iterator itbegin = vetRecvData.begin();
    vetRecvData.erase(itbegin);
    //重新调用当前函数,递归判断
    return JudgeValidData(vetRecvData, nTotalSize);
}

3:包头匹配后,判断是否达到了数据包的固定协议长度?

在这里说的固定协议长度,就是数据内容之前的字节,在这篇文章中,数据内容之前有19个字节,所以,当vetRecvData的数据总长度 < 19个字节时,不需要处理。

当达到固定协议长度后,说明该缓冲区中存在了有效数据,那么就需要判断实际的数据内容是否达到了整包的标准?

4:判断有效数据是否接收完整?

首先,需要获取当前包需要接收的数据长度。在这里是占用三个字节,分别是: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;

如果当前vetRecvData缓冲区的数据 < nTotalSize,说明数据不完整,不判断;反之,缓冲区中存在完整的数据。

5:数据校验位判断

最后,判断下缓冲区完整包的最后一位是否是校验位?

这样,才算是一个完整的一条数据包!

到这里,就算判断完成了,由此可以从一个大的缓冲区中抽取出有用的一组数据。

内部的判断逻辑讲解完之后,接下来就是外部数据使用了。继续上面的这段代码继续讲解~

int nTotalSize = 0;
while(this->JudgeValidData(vetRecvData, nTotalSize) == ture)
{
    //接收到了完整包,对包进行处理
}

接收到一个完整包之后,数据处理过程

1:根据nTotalSize大小从缓冲区中获取有效内容

2:截取出剩余的缓冲区内容,重新赋值

3:对一个完整包数据进行业务处理

将流程转换成代码,如下:

int nTotalSize = 0;
while (this->JudgeValidData(vetRecvData, nTotalSize) == true)
{
	//这一条数据被处理之后,使用一个临时容器存储 处理的 通讯数据
	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]);
	}
	//删除 存储所有接收字节的容器 中的数据
	vetRecvData.clear();
	vetRecvData = vetValidData; //重新更新数据信息
	//接收的是整包数据时,进行实际的数据处理
	ProcessingPancelValidData(chUseData, nTotalSize);
	delete[] chUseData;
	chUseData = nullptr;
}

以上就是C++实现TCP客户端及服务器Recv数据筛选处理详解的详细内容,更多关于C++ 客户端 服务器数据筛选的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++基于boost asio实现sync tcp server通信流程详解

    目录 一.功能介绍 二.string类型数据交互 2.1 程序源码 2.2 编译&&执行 2.3 程序执行结果 三.byte类型数据交互 3.1 程序源码 3.2 编译&&执行 3.3 程序执行结果 一.功能介绍   基于boost asio实现server端通信,采用one by one的同步处理方式,并且设置连接等待超时.下面给出了string和byte两种数据类型的通信方式,可覆盖基本通信场景需求. 二.string类型数据交互   规定server与client双方

  • C++多线程实现TCP服务器端同时和多个客户端通信

    通讯建立后首先由服务器端发送消息,客户端接收消息:接着客户端发送消息,服务器端接收消息,实现交互发送消息. 服务器同时可以和多个客户端建立连接,进行交互: 在某次交互中,服务器端或某客户端有一方发送"end"即终止服务器与其的通信:服务器还可以继续接收其他客户端的请求,与其他客户端通信. 服务器端 #include <WinSock2.h> #include <WS2tcpip.h> #include <iostream> using namespa

  • 基于C++实现TCP聊天室功能

    本文实例为大家分享了C++实现TCP聊天室功能的具体代码,供大家参考,具体内容如下 TCPServer.cpp: // TCPServer.cpp : Defines the entry point for the console application. #include "stdafx.h" #include<iostream> #include<stdio.h> #include<WinSock2.h> using namespace std;

  • C++、python和go语言实现的简单客户端服务器代码示例

    工作中用到了C/S模型,所做的也无非是给服务器发数据,但开发阶段会遇到程序自身的回环测试,需要用到简单的服务端以便验证数据发送的正确性. 写软件用C++,跑测试用python,这段时间也刚好看go语言,所以都要有demo.以下三组程序实现的功能相同,这里一起做下总结. 一.C++实现 Boost.Asio是一个跨平台的C++库,它用现代C++方法为网络和底层I/O程序提供了一致的异步I/O模型. 为了跨平台,我用boost库实现,具体如下. 服务端代码: 复制代码 代码如下: /*      F

  • C++ Socket实现TCP与UDP网络编程

    目录 前言 TCP 1). 服务器 2). 客户端 3). TCP聊天小项目 UDP 1). 服务器 2). 客户端 总结 前言 socket编程分为TCP和UDP两个模块,其中TCP是可靠的.安全的,常用于发送文件等,而UDP是不可靠的.不安全的,常用作视频通话等. 如下图: 头文件与库: #include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") 准备工作: 创建工程后,首先右键工程,选择属性 然后选择 C/C++

  • C++实现TCP客户端及服务器Recv数据筛选处理详解

    目录 正文 代码解析 1:当Tcp缓冲区的数据小于3个字节时,不进行判断 2:判断包头是不是一致? 3:包头匹配后,判断是否达到了数据包的固定协议长度? 4:判断有效数据是否接收完整? 5:数据校验位判断 正文 对于一个简单的tcp通讯这里我就不再讲述了,今天主要为大家讲解下,如何从::recv中筛选出一个完整包逻辑. 就简单的以客户端为例(服务器接收方也是同样的逻辑),假设服务器一直在频繁发送数据,在recv函数中并不能保证每次接收的都是一个完整的包,当设置recv的缓冲区过大时,就会出现多个

  • Go语言服务器开发之客户端向服务器发送数据并接收返回数据的方法

    本文实例讲述了Go语言服务器开发之客户端向服务器发送数据并接收返回数据的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: package mysocket    import (      "fmt"      "io"      "net"  )    func MySocketBase() {      var (          host   = "www.apache.org"         

  • 浅谈Android客户端与服务器的数据交互总结

    前言: 本文总结了Android客户端与服务器进行交互时,采用RESTful API +Json的交互方式,针对不同的数据形式以及不同的解析方法,如有不足之处,欢迎指正. 温馨提示:本文适合有一定Android开发经验的人阅读,如有疑问,欢迎留言讨论. 先了解一下相关的基本概念. 1. Android客户端与服务器端通信方式 通信方式主要有HTTP和Socket. HTTP通信:即使用HTTP协议进行通信,工作原理是客户端向服务器端发送一条HTTP请求,服务器收到之后先解析客户端的请求,之后会返

  • spring boot udp或者tcp接收数据的实例详解

    下面用的是 springboot内置integration依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-integration</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot<

  • python静态web服务器实现方法及代码详解

    1.编写TCP服务器程序. 2.获取浏览器发送的http请求消息数据. 3.读取固定的页面数据,将页面数据组装成HTTP响应消息数据并发送给浏览器. 4.HTTP响应报文数据发送完成后,关闭服务于客户端的套接字. 实例 # 时间: 2021/10/21 20:38 import socket if __name__ == '__main__': # 创建tcp服务端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_

  • Python实现监控远程主机实时数据的示例详解

    目录 0 简述 1 程序说明文档 1.1 服务端 1.2 客户端 2 代码 0 简述 实时监控应用程序,使用Python的Socket库和相应的第三方库来监控远程主机的实时数据,比如CPU使用率.内存使用率.网络带宽等信息.可以允许多个用户同时访问服务端.注:部分指令响应较慢,请耐心等待. 1 程序说明文档 1.1 服务端 本程序为一个基于TCP协议的服务端程序,可以接收客户端发送的指令并执行相应的操作,最终将操作结果返回给客户端.程序运行在localhost(即本机)的8888端口. 主要功能

  • Redis客户端及服务端的安装教程详解

    本系列将和大家分享Redis分布式缓存,本文是该系列的开篇,主要简单介绍下Redis客户端及服务端的安装. 一.Redis简介 Redis:Remote Dictionary Server 远程字典服务器 基于内存管理(数据存在内存),实现了5种数据结构(分别应对各种具体需求),单线程模型的应用程序(单进程单线程),对外提供插入--查询--固化--集群功能. 正是因为基于内存管理所以速度快,可以用来提升性能.但是不能当数据库,不能作为数据的最终依据. 单线程多进程的模式来提供集群服务. 单线程最

  • SQLServer设置客户端使用IP地址登录的图文详解

    一.设置SQLServer身份验证 1.按下windows+R,弹出运行框. 2.在弹出框中输入cmd,按下enter键. 3.在dos命令窗口输入compmgmt.msc命令,按下enter键. 4.在计算机管理窗口->展开服务和应用程序->展开SQLServer配置管理器->展开SQLServer网络配置->点击MSSQLSERVER的协议. 5.右键点击TCP/IP->点击启用->点击弹出框中的确定. 6.在TCP/IP弹出框->找到IP2->已启用由

  • Kubernetes存储系统数据持久化管理详解

    目录 引言 安装存储系统 PV PVC StorageClass 安装NFS Provisioner 使用StorageClass 总结 引言 Kubernetes为了能更好的支持有状态应用的数据存储问题,除了基本的HostPath和EmptyDir提供的数据持久化方案之外,还提供了PV,PVC和StorageClass资源对象来对存储进行管理. PV的全称是Persistent Volume(持久化卷),是对底层数据存储的抽象,PV由管理员创建.维护以及配置,它和底层的数据存储实现方法有关,比

  • C#中WPF ListView绑定数据的实例详解

    C#中WPF ListView绑定数据的实例详解 WPF中ListView用来显示数据十分方便, 我们可以将它分成几个列,每一个列用来显示一条数据,但是又是在一方之中. 那么怎样实现这样的效果的呢,这就要用绑定了. 我们先来看一看他的xmal代码 <ListView Name="receiveList" Grid.Row="0"> <ListView.View> <GridView> <GridView.Columns>

随机推荐