TCP偶尔丢失数据

fxwzzbd 2016-06-01 03:01:24
传输格式采用:长度+内容,先传4字节长度,再传具体内容。大多数时候正常,但客户端有时候收不到内容的头4个字节,服务器有时候会收不到内容的最后4个字节。请问会是什么原因,谢谢!
...全文
327 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
_船长_ 2016-06-03
  • 打赏
  • 举报
回复
引用 11 楼 jzycode 的回复:
解决TCP粘包问题,个人不推荐采用先发送代表长度的四个字节,然后再发送数据部分,因为在IP层,会尽量一次尽可能多的发送数据,比如:调用send发送连续发送如下几个数据包, 包1:[4字节],包2:[500字节]; 包3:[4字节],包4:[520字节]; 包5:[4字节],包6:[530字节]; 一共大小为:1562个字节,在IP层,会尽量将多个小包组合在一起发送(尽量的原因是这两个包的发送间隔时间不太长),根据IP层的MTU(1460)大小,分两次发送到网络上,第一次发送:1460个字节,第二次发送:102个字节 到达对端时,触发了两次FD事件,按照你的解析,触发第一次FD事件后,先读取4个字节,读到了第一个包的内容为500个字节,解析出来第一个数据包:[长度(4字节) + 内容(500字节)],接着再处理第二次FD事件,先读取4个字节,获取到第二个包的内容为520个字节,解析出来第二个数据包:[长度(4字节) + 内容(520字节)],这样,解析数据包的任务结束了,可时间上,第三个数据包还没有解析,还留在了SOCKET缓冲区中,因此,这种靠FD事件触发recv的方式去解析数据包的方式,会导致丢包。 如果你的代码再写的不好,那基本上丢包是肯定的。
我说的这种方式,其实存在个问题,我忽略了一个情况,当上一个recv调用返回后,如果SOCKET缓冲区中存在数据,还会再次触发FD事件,所以一般而言,如果代码写的没有问题,不会存在在解析上的丢包问题,这一点需要更正下, 之所以提到你的这种解析方式存在问题,比如发送了两个数据包: 包1:[4字节];包2:[500字节] 就是一种很极端的情况,网络情况很差,差到了,对端第一次只接收到了3个字节,触发了一次FD事件,你接收到了3个字节,要想获取到数据包的长度,还差一个字节,你还需要再接收一个字节,如果你的代码,没有考虑这种极端情况,数据包的解析势必会出现问题,所以,我的做法:只管接收,把接收到的数据,按照接收顺序存放到一个缓冲区中,然后我通过缓冲区中的数据进行解析,解析完一个数据包,就从缓冲区清除掉,这样,不管网络情况有多么的差劲,只要发过来的数据没有问题,我的解析就不会出现问题。 如果不设置代表包的长度字段,是没法很好的处理粘包的问题,这就是因为TCP协议是没有消息边界的,是基于流式的。
fxwzzbd 2016-06-03
  • 打赏
  • 举报
回复
To jzycode: 谢谢!
赵4老师 2016-06-02
  • 打赏
  • 举报
回复
建议楼主先学会使用抓包软件比如wireshark
赵4老师 2016-06-02
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://bbs.csdn.net/topics/380167545
fxwzzbd 2016-06-02
  • 打赏
  • 举报
回复
如果没有长度,请问要怎么找到消息边界,谢谢
fxwzzbd 2016-06-02
  • 打赏
  • 举报
回复
To jzycode: 谢谢您的提醒,如果只有2次FD事件,那确实会丢包,请问要怎么处理?谢谢
fxwzzbd 2016-06-02
  • 打赏
  • 举报
回复
谢谢各位回复,服务器接收有时候少后4个字节原因找到了,是因为多线程引起的: senddata(lenbuf); senddata(databuf); 是这样发送的,是在senddata里面加的锁,现在改成2条一起发就没有问题了 至于客户端少收开头4字节,今天一直没有出现,估计也有可能是这个原因引起的。 再次表示感谢!
_船长_ 2016-06-02
  • 打赏
  • 举报
回复
解决TCP粘包问题,个人不推荐采用先发送代表长度的四个字节,然后再发送数据部分,因为在IP层,会尽量一次尽可能多的发送数据,比如:调用send发送连续发送如下几个数据包, 包1:[4字节],包2:[500字节]; 包3:[4字节],包4:[520字节]; 包5:[4字节],包6:[530字节]; 一共大小为:1562个字节,在IP层,会尽量将多个小包组合在一起发送(尽量的原因是这两个包的发送间隔时间不太长),根据IP层的MTU(1460)大小,分两次发送到网络上,第一次发送:1460个字节,第二次发送:102个字节 到达对端时,触发了两次FD事件,按照你的解析,触发第一次FD事件后,先读取4个字节,读到了第一个包的内容为500个字节,解析出来第一个数据包:[长度(4字节) + 内容(500字节)],接着再处理第二次FD事件,先读取4个字节,获取到第二个包的内容为520个字节,解析出来第二个数据包:[长度(4字节) + 内容(520字节)],这样,解析数据包的任务结束了,可时间上,第三个数据包还没有解析,还留在了SOCKET缓冲区中,因此,这种靠FD事件触发recv的方式去解析数据包的方式,会导致丢包。 如果你的代码再写的不好,那基本上丢包是肯定的。
_船长_ 2016-06-02
  • 打赏
  • 举报
回复
引用 7 楼 fxwzzbd 的回复:
server端还好理解,客户端为什么会少了开头4个字节,而且检测到读事件后,recv的数据少了前面4个字节,然后马上又可以检测读事件,但再recv返回10035,很奇怪,既然有读事件,为什么recv又返回WSAEWOULDBLOCK呢?
返回10035,说明当前在SOCKET缓冲区中没有数据可读,可能原因(如果分析的不对,勿喷):你上一次,一下子把数据全部读走了,导致这次没有可以读取的数据。 比如:对端过来150个字节的数据,触发了FD事件,你调用recv去接收,但你接收的长度为300,在将要接收之前,对端又来了100个字节的数据,再次触发FD事件,目前,缓冲区中一共有250个字节,你打算再次调用recv去接收,在这个间隙中,上一次调用的recv一下子把缓冲区的数据全部取走了(因为接收长度为300),并且返回接收长度为250,所以导致下一个recv调用返回10035。 至于为什么接收会少4个字节,肯定是代码问题,把主要代码发来,大家帮你看看
fxwzzbd 2016-06-01
  • 打赏
  • 举报
回复
server端还好理解,客户端为什么会少了开头4个字节,而且检测到读事件后,recv的数据少了前面4个字节,然后马上又可以检测读事件,但再recv返回10035,很奇怪,既然有读事件,为什么recv又返回WSAEWOULDBLOCK呢?
xian_wwq 2016-06-01
  • 打赏
  • 举报
回复
server端没有收足指定的长度,继续接收, 如果数据格式异常,断开连接, 让客户端重新发。
fxwzzbd 2016-06-01
  • 打赏
  • 举报
回复
从系统缓冲区读出来就写入日志了,就少了4个字节,不过只写入了内容,长度没有写
Eleven 2016-06-01
  • 打赏
  • 举报
回复
会不是接收处理端有问题?
oyljerry 2016-06-01
  • 打赏
  • 举报
回复
先在一些可疑的地方添加日志等,多收集一些信息后面来分析
fxwzzbd 2016-06-01
  • 打赏
  • 举报
回复
谢谢LS回复,缓冲区有4096字节,定义的消息长度最长才200多字节,发送返回值和接收返回值都检查了,至于抓包检查不太好办,问题是从昨天日志里面发现的,以前和今天一切正常,不知道啥时候会出现。不过好像和网络有关,当网络状况不好时,容易出现
笨笨仔 2016-06-01
  • 打赏
  • 举报
回复
检查缓冲区长度和验证发送返回值,或抓包检查

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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