TCP协议.之发送数据,粘包,拆包问题(二)

Tcp协议发送数据,粘包,拆包问题,这句话本身是错误的,tcp是协议,发送接收数据时并不会粘包,tcp,ip,只负责传输数据
粘包是应用层解析数据时,包1和包2粘连在一起,解析数据时,出现错误的,网络中,很多博主,就没搞清楚。

send,发送频率太快,发送包的时候,有可能发送1400字节,或100个字节,按流的方式发送,应用层很快频率,非阻塞去recv数据时,不一定能读到1400个字节,可能只有1000个,下次再去读取时,读到应用层发送的第一包里的后400个字节开头的数据包,出现粘包,解析数据头是出错,其实tcp传输数据时,没有包的概念,和uart串口一样,只有流的概念,tcp协议讲的很清晰,tcp是面向流的,一个一个字节流,
tcp传输时,只按流的方式发送,没有一包一包的概念,假如发送数据很大,tcp协议,自动分成多包一个一个字节进行发送,接收端接收到数据,会自动按包号,进行组合假如分成1,2,3,4,5包,接收端接收到1,2,4,5,底层协议自动组合,错误将自动重传,所以,tcp是可靠的传输。

这个包和应用层send发包不是一个概念,udp才是面向报文的,应用层按包发送接收,发送1400字节的包,udp只要网络正常,基本一定能收到1400个字节的包,tcp不一定能recv能接收到1400个字节,所以如果用结构,去解析包头,数据段的数据,这时候,有可能就回错误,包头校验不对,如下一段代码,用结构类型去解析接收buf的数据,注意,我这里qt的read接收的,linux是recv。

	PT_udpSocketDataPkt _tDataPkt1 = (PT_udpSocketDataPkt)this->databufer2;
	memset(_tDataPkt1, 0, sizeof(T_udpSocketDataPkt));

	int rcvlen = ClientTcpSocket->read((char*)_tDataPkt1, UDP_MAX_LEN);//最多读1400个
	if(rcvlen <= 0)
	{
	    QMessageBox::information(this, CCODE("提示"), CCODE("接收服务端数据失败!"));
	}
	else if ( ( (rcvlen >= UDP_MIN_LEN) && (rcvlen <= UDP_MAX_LEN) )  \
	&& (_tDataPkt1->DataHead.u32Sync == PKT_SYNC) && (_tDataPkt1->DataHead.u8Cmd = CMD_SNAP_PIC_CMD_ACK))
	{
		if (_tDataPkt1->DataHead.u16TotalPktNum != _tDataPkt1->DataHead.u16CurrentPktSn)//接收到一包数据
		{
		}
	}
			

如果服务端发数据够快,客服端读取数据时,就可能解析不对,也是被udp干扰了,写udp时,就是按包发送,接收,去解析的,没问题。
放到tcp就有可能有问题。
csdn很多博主,在解决粘包问题时,其中解决方法,是这样建议的,没有考虑这个问题,什么极端情况都可能出现的。

tcp应用层解析数据时,发送大量数据,很有可能会出现这样情况,上面的方法其实也可以在某系业务时可用,如发送频率较慢,几ms发送数据,接收端慢一点,能及时处理读取全部数据,并且回复发送端,收到已处理消息,接收端再发送,就可以这样,但是发送数据很慢,传输一个几mb的文件,很慢,这样用udp协议也可以了,就没必要用tcp了,tcp就是可靠。

如果是传输大文件时,只需发送方告诉接收方,文件的大小,接收按流的方式读取到buf里,recv多少个字节,就放到buf里,直到收完大小为止,后者,很多人建议的。
如果事先不知道文件大小,也可以这样做,在数据里,加结束标志如\\\,读到包结束标志后,表示完整包发送完毕。

需要处理大量数据时,最好还是按流的方式处理数据,放到buf里,如果数据是报文,消息,可以加标志位,应用层根据结束标志位,在流buf里,寻找一个完整的包,如果是连续的文件,接收多少个字节,就按多少个字节拼接到buf里。

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Netty中的TCP问题是由于底层的TCP协议无法理解上层的业务数据而导致的。为了解决这个问题,Netty提供了几种解决方案。其中,常用的解决方案有四种[1]: 1. 固定长度的器(FixedLengthFrameDecoder):将每个应用层数据分成固定长度的大小。这种器适用于应用层数据长度固定的情况。 2. 行器(LineBasedFrameDecoder):将每个应用层数据以换行符作为分隔符进行分割分。这种器适用于应用层数据以换行符作为结束符的情况。 3. 分隔符器(DelimiterBasedFrameDecoder):将每个应用层数据通过自定义的分隔符进行分割分。这种器适用于应用层数据以特定分隔符作为结束标志的情况。 4. 基于数据长度的器(LengthFieldBasedFrameDecoder):将应用层数据的长度作为接收端应用层数据分依据。根据应用层协议含的数据长度进行。这种器适用于应用层协议数据长度的情况。 除了使用这些器,还可以根据业界主流协议的解决方案来解决问题[3]: 1. 消息长度固定:累计读取到长度和为定长LEN的报文后,就认为读取到了一个完整的信息。 2. 使用特殊的分隔符:将换行符或其他特殊的分隔符作为消息的结束标志。 3. 在消息头中定义长度字段:通过在消息头中定义长度字段来标识消息的总长度。 综上所述,Netty提供了多种解决方案来解决TCP问题,可以根据具体的业务需求选择合适的解决方案[1][3]。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rjszcb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值