有人遇到过tcp的zerowindow问题么?跪求各位大神指点迷津~~ 200送上

redleaves 2012-09-21 01:18:41
事情是这样,我实现了个rtsp服务器.网络层使用了epoll模型.
在有些情况下,一些客户端连上来以后,会发生zerowindow的问题.

于是,我把发送策略改了一下. 情况有所好转.但不能彻底解决问题.
之前的发送方式是(方案A),数据包先进缓冲,一次投递过程结束后/缓冲满以后,再整体投递到网络上.
现在的发送方式是(方案B),数据包先投递,如果没有发送完全,则放到缓冲等待下次投递过程.

这两种方式产生的区别是.当一个视频帧被拆分成多个数据包投递时.方案A会把几个视频包一起投递.而方案B则尽可能的把数据包分别投递,但无法避免合并投递的问题.整个过程用wireshark分析后,并没有发现错误数据包.应该不存在数据处理逻辑的错误.

按理说,客户端发生zerowindow是因为客户端收数据不及时,或发送数据太多导致.当zerowindow后,发送端会等待接收端收取数据.
但是,当发生这个问题以后,客户端就再以不处理数据了,一直处于zerowindow状态.于是,服务器就一直死等.直到超时断开链接.
我在网上搜索,发现也有人遇到过这种问题,但最后解决了...不知道是如何解决的?似乎还有人说,出现zerowindow后,他select不到事件了...

怎奈,客户端是现成的...没法调试,更没法修改.
还有什么原因,会造成这种问题呢?
跪求各位大神指点迷津~~
...全文
4521 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
redleaves 2012-10-21
  • 打赏
  • 举报
回复
问题没法解决了...他们自己的东西有BUG...实在不知道怎么折腾.
也没人接分?
redleaves 2012-09-24
  • 打赏
  • 举报
回复
暂时没解决问题.只是检查他们RTP代码时,发现了几个经典BUG.
一处,switch穿透BUG. 漏了个break
一处,if挂接BUG,原本代码
if (xxx )
log(xxx);
结果log行被注释掉了,而if没有{}...挂接到下一个逻辑上去了.
一处,Ctrl-C/V引起的BUG.两个BUFF,一个是xxx1,一个是xxx2.
send(xxx1);
send(xxx1);//这里应该是xxx2
还有一堆硬逻辑问题,比如找jpeg数据段,直接加偏移...完全不按jpeg的逻辑来.只要数据源有变化,肯定错的一塌糊涂...

真是晕了.
冷月清晖 2012-09-24
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 的回复:]

对于这个问题,我现在有几个怀疑的地方.
1.驱动. 因为网络驱动是别人改过的.之前处理UDP广播就有点问题.我也大概看过他们是如何移植的---仅仅是把不能编译的代码注释掉...所以这个地方比较令人怀疑.不过就debian的测试结果来说,可能是没问题的.
内核倒是没怀疑过.只是不知道是否会因为我的误用,从而导致这种问题.
2.播放器. 有播放器在我改了发送策略后问题消除.说明播放器的处理逻辑……
[/Quote]

嗯,可能性还是比较多的,楼主解决后一定要来分享下经验。

ps:一般这种问题上层软件能解决的公司都不会动底层的代码或硬件部门,都是我们做上层的来改,杯具啊。
redleaves 2012-09-23
  • 打赏
  • 举报
回复
ET是什么名堂?
redleaves 2012-09-23
  • 打赏
  • 举报
回复
对于这个问题,我现在有几个怀疑的地方.
1.驱动. 因为网络驱动是别人改过的.之前处理UDP广播就有点问题.我也大概看过他们是如何移植的---仅仅是把不能编译的代码注释掉...所以这个地方比较令人怀疑.不过就debian的测试结果来说,可能是没问题的.
内核倒是没怀疑过.只是不知道是否会因为我的误用,从而导致这种问题.
2.播放器. 有播放器在我改了发送策略后问题消除.说明播放器的处理逻辑会受发送策略影响.而且同一个播放器,同样是RTSP over TCP,同一个数据流.用不同的操作播放,一个操作可以成功,一个操作肯定失败...
3.RTSP有问题. 这个好办,我自己写的代码,想怎么查都可以.但至今没查出什么问题.最有可能引起问题的,就是可能有数据包处理时序的问题.但用wireshark也没查出问题,包括数据流重建,也是成功的.只有一点就是wireshark说mjpeg最后一个有mark的数据包的timestamp有问题.我也没看出来问题在哪.rfc上就说同一帧用一个时间戳啊.另外,并不是所有播放器都有问题...
4.MJPEG的数据封装有问题. 因为MJPEG的图像数据不是我实现的,是由硬件直接提供的,没有办法仔细验证它代码.而且只有少数几个MJPEG解码器可以正确解码它.有的播放器会因为MJPEG数据有问题而崩溃.这可能成为播放器卡死的一个原因.
5.RTP封装有问题. 这玩意是别人改FFMPEG的,改的比较乱.旧版还能工作,新版干脆就不工作了.我打算重新自己写个试试.

暂时有这么些怀疑的点.现在重点怀疑2,4,5.没办法,只好自己都再实现一遍.

还有什么其它没想到的,欢迎大家帮我出谋划策.最好是能有实际案例以及具体解决方法.
qq120848369 2012-09-23
  • 打赏
  • 举报
回复
还是得找代码的问题,木有办法。

首先别怀疑内核。。。TCP/IP, epoll已经久经沧桑了。。

其次别怀疑自己。。。

这种郁闷的BUG是很烦人的,别着急,可以找同事一起review一下代码实现,确保大家都找不出问题来,然后再怀疑客户端。

redleaves 2012-09-23
  • 打赏
  • 举报
回复
在服务器端,epoll中我的确是用的是边缘触发模式.但这对于发送不会造成实质性影响.因为数据包发送过程,是由数据采集对象主动推送的,每个推送过程都会主动尝试send.而不是收epoll的可写事件驱动,epoll的写事件只用来清空缓存.
而且我把epoll换成poll,同样有问题...有空了再试下epoll的电平触发模式,我想应该和用poll是一样的效果.
qq120848369 2012-09-23
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 的回复:]

ET是什么名堂?
[/Quote]

edge trigger。
冷月清晖 2012-09-22
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 的回复:]

引用 9 楼 的回复:tcp协议对0窗口问题是用坚持定时器,定时器到了就会发查询包。你在tcp层上做得应用和这些都没有关系,不管发包频率,包大小或窗口大小,有问题始终是有问题,只是复现的频率不一样。
你只能控制定时器时间,以及窗口阀值避免糊涂敞口综合症。
抓包,如果服务器在客户端0窗口后一定时间内发相同ack的查询包,服务器没有问题。
如果客户端响应的查询包window始终是0,客户端程……
[/Quote]

关键问题还是看不到客户端的源码。
qq120848369 2012-09-22
  • 打赏
  • 举报
回复
ET?
redleaves 2012-09-22
  • 打赏
  • 举报
回复
有哪位大大有解决这个问题的经验,跪求分享~~~
Geoff08Zhang 2012-09-21
  • 打赏
  • 举报
回复
流媒体数据以何种方式传输双方是可以协商的.RTSP传输的通常是控制命令:play, setup, pause等.流媒体数据部分可以走RTP,也可以走RTSP(Embedded (Interleaved) Binary Data).RTP的底层协议是UDP,而RTSP底层使用TCP.从你的情况看使用的是TCP,出现0窗口是因为客户端接收数据太慢或缓冲区太小.解决方案:
1. 协商时服务器回客户端使用RTP/UDP方式,UDP不存在0窗口问题,缓冲区满数据丢弃.
2. 如果客户端不支持 RTP/UDP方式,服务器端可以适当降低发送速率.
socket编程可以参考《WinSock网络编程经络》,这里有源码下载:http://download.csdn.net/detail/geoff08zhang/4571358
redleaves 2012-09-21
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]tcp协议对0窗口问题是用坚持定时器,定时器到了就会发查询包。你在tcp层上做得应用和这些都没有关系,不管发包频率,包大小或窗口大小,有问题始终是有问题,只是复现的频率不一样。
你只能控制定时器时间,以及窗口阀值避免糊涂敞口综合症。
抓包,如果服务器在客户端0窗口后一定时间内发相同ack的查询包,服务器没有问题。
如果客户端响应的查询包window始终是0,客户端程序有问题,说明并未取走数……[/Quote]理是这个理,但问题在于,改了发送策略对这个问题有所改进.至少我自己这边测试是没问题了.而且同样的播放器,用其它的媒体服务器,也不会出这个问题.就说明有改进空间.
最关键的在于,验收不是我说了算...
而且我一直找不到问题的关键点.TCP的实现上,出错的可能性应该比较小.我在debian的stable版上运行服务器也同样会出这个问题.
ddcelf 2012-09-21
  • 打赏
  • 举报
回复
UDP基础上做,客户端0窗口直接丢弃,然后插值自己计算,当然不会出问题了。
ddcelf 2012-09-21
  • 打赏
  • 举报
回复
tcp协议对0窗口问题是用坚持定时器,定时器到了就会发查询包。你在tcp层上做得应用和这些都没有关系,不管发包频率,包大小或窗口大小,有问题始终是有问题,只是复现的频率不一样。
你只能控制定时器时间,以及窗口阀值避免糊涂敞口综合症。
抓包,如果服务器在客户端0窗口后一定时间内发相同ack的查询包,服务器没有问题。
如果客户端响应的查询包window始终是0,客户端程序有问题,说明并未取走数据。
如果怀疑tcp实现有问题,可以专门写测试程序,不需要和你们的应用混在一起。
redleaves 2012-09-21
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]我们以前是在UDP基础上自己封装协议做的,不用RTP/RTCP。可能就不存在这个问题了。
-------------
你这个问题用B方案的话出现概率大么? 可以考虑重连么。[/Quote]好像不怎么出了.但问题还是存在.因为别人还会遇到.
如果播放器是自己做,问题就好办多了....
冷月清晖 2012-09-21
  • 打赏
  • 举报
回复
我们以前是在UDP基础上自己封装协议做的,不用RTP/RTCP。可能就不存在这个问题了。

-------------

你这个问题用B方案的话出现概率大么? 可以考虑重连么。
redleaves 2012-09-21
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]你适当控制降低下发送的速率试试呢。[/Quote]这个我试过,有一定的效果.但不能解决问题,而且实际应用环境里,不能这么干...
事实上,我在改发送策略之前,改过发送缓冲的大小.当发送缓冲比较大的时候,很容易出现这个问题.而发送缓冲较小(只能容下1.5个包)时,情况就会好很多.所以我才会改发送策略.
这也让我怀疑客户端的数据处理机制有问题.对于合并发送的数据处理不了.但TCP不可能把投递了一半的数据撤销回来,也不能保证一次投递一个完整的包.所以,不做发送缓冲是不可能的.难道我要每次投递前要检查发送窗口,如果不能容下一个包就不发数据?
冷月清晖 2012-09-21
  • 打赏
  • 举报
回复
你适当控制降低下发送的速率试试呢。
redleaves 2012-09-21
  • 打赏
  • 举报
回复
客户端在PC上,CPU占用2%
加载更多回复(3)

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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