串口数据接收完整,如何进行粘包

艳艳lisa 2016-09-20 11:19:37
需求:
1.串口接收多种类型的数据,固定包头+长度。
2.按照接收的数据类型进行相应处理

问题:
1.串口接收的数据不完整,多个包粘在一起发送过来。
2.完整的数据包解析出来之后,最后一个包只有一部分数据,如何和下次接收的数据进行重组,避免丢包的情况发生?

环境:
VC++6.0
串口收发使用 PComm库




...全文
2141 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
用户 昵称 2016-09-26
  • 打赏
  • 举报
回复
循环缓冲,多级缓冲。
lonelyhacker 2016-09-21
  • 打赏
  • 举报
回复
假设发送的数据长度是1000个字节。包头假设是0xFF.分成3个数据包,每个数据包是否有包头呢?数据的长度是每个包的长度呢?还是总得长度呢? 有长度,自然就根据长度来读取就可以了。读不完的情况只能说是下位机和上位机的时间没匹配上。 比如,下位机发了1000个字节,上位机需要读取1秒的时间才能读取完,结果你读了500ms,那肯定是读不完整的。读取的时间还跟你的波特率和数据大小有关。 比如你下位机只发了1000个字节,你上位机循环读1000次,每次读一个字节,一个字节花20ms,数据估计就全了。
hhhh63 2016-09-21
  • 打赏
  • 举报
回复
我的方法是,建一个通讯线程,申请一个缓冲,一直循环收,收够了把数据移到指定结构中让主线程处理,通讯线程把上次多收到移到缓冲头部,继续收发循环。用的CSerialPort插件,方法是一样的,相关代码如下,供参考,祝好运。

	// 读数据
	// m_bSend == FALSE 读下位机数据	//@00FA00400000000101000000000000059D000066FB203B00020000000000089815CB29C4974D03B50085B54E*\r	// 正常返回16个字
	// m_bSend == TURE 读下位机数据 "@00FA00400000000102000040*\r"
	ASSERT( sizeof( m_pReadBuffer ) > nReadLen );
	int len = m_serialPort.Read( m_pReadBuffer, nReadLen );	// 上传数据,格式参见网络记事
	if( !len )					// 考虑一次读不完的情况
	{
		if( m_bKilling )
			return TRUE;	// 正在终止线程,不抛出异常,直接返回

		THROW( new HException( L"接收数据错误1" ) );
	}
	if( m_bKilling )
		return TRUE;	// 正在终止线程,直接返回

	while( len < nReadLen )	//粘包
	{
		int len2 = nReadLen - len;
		len2 = m_serialPort.Read( m_pReadBuffer + len, len2 );
		if( !len2 )					// 考虑一次读不完的情况
		{
			THROW( new HException( L"接收数据错误2" ) );
			if( m_bKilling )
				return TRUE;	// 正在终止线程,不抛出异常,直接返回

		}
		if( m_bKilling )
			return TRUE;	// 正在终止,直接返回

		len += len2;
	}
	if( m_bKilling )
		return TRUE;	// 正在终止,直接返回

	return result;
sevancheng 2016-09-21
  • 打赏
  • 举报
回复
读包头,再根据长度,读取数据,或者自己建立缓冲区,把收到数据放进缓冲区,再去缓冲区处理一包一包的数据
阿源是少年 2016-09-21
  • 打赏
  • 举报
回复
先读固定长度包头,每次读取都做一个计数,直到接收的字节等于包头长度为止,这种情况只会少收,不会多收的,然后解析包头得到包体长度,对于包体的读取与包头的读取逻辑一致
sxqinge 2016-09-20
  • 打赏
  • 举报
回复
那你这就很好处理了,通过waitformultipleobject(是这么拼写吧)来获取事件类型,处理是发送还是接收指令,只处理当前的接收,发送之前清空接收缓存,获取到有效数据包就完成发送/接收回合操作 至于包的完整性,有很多方法的
艳艳lisa 2016-09-20
  • 打赏
  • 举报
回复
引用 1 楼 sxqinge 的回复:
1、根据协议对数据包进行解析,遍历提取有效数据包; 2、一般情况下,每发送一条指令,会有对应的响应指令。处理完响应后,再发送下一个读取指令。 但也有这种情况,即发送和读取是分两个线程进行,而不是半双工的异步方式,那么就需要定义个容器list/vector来存储接收到的字节,再处理接收容器时,从头开始遍历读取有效数据包,不论是否有效的,读完就将其清掉。但这样要考虑互斥操作。
1.如果接收一次数据是完整的话,可以提取,就是不太清楚怎么讲末尾不完整的数据包和下一次接收的数据进行组合; 2.我这种情况是接收一次指令,响应一次,发送和读取在一个线程中。
sxqinge 2016-09-20
  • 打赏
  • 举报
回复
1、根据协议对数据包进行解析,遍历提取有效数据包; 2、一般情况下,每发送一条指令,会有对应的响应指令。处理完响应后,再发送下一个读取指令。 但也有这种情况,即发送和读取是分两个线程进行,而不是半双工的异步方式,那么就需要定义个容器list/vector来存储接收到的字节,再处理接收容器时,从头开始遍历读取有效数据包,不论是否有效的,读完就将其清掉。但这样要考虑互斥操作。
赵4老师 2016-09-20
  • 打赏
  • 举报
回复
仅供参考: 不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧