Linux中流式TCP/IP在无线Modem上丢失小包

Kingron 2010-03-16 10:08:24
感谢关注这个问题。

我们在Linux下开发一个网络客户端程序(服务器是不可修改的),不断向服务器不定期发送一些很小的包(一般只有几十字节),现在出现这种情况:大部分包正常发送,但是当无线Modem断开的时候,如果这个时候刚好有一个小包,就可能丢失,但在程序中却显示已经发送成功,导致丢包。
我们分析原因是这样:
1:主程序创建Socket,TCP/IP方式,并采用Stream方式
2:主程序调用Write,写入小包到系统的Socket缓冲区,并返回成功写入,由于字节数很小,所以一般都立即返回写入成功!
3:Linux TCP/IP协议栈把Socket缓冲区数据发送到服务器

如果第二步完成,刚好在第三步出现无线Modem断开的情况,就会导致主程序以为已经发送成功了,但服务器收不到的情况。
我们在网络上搜索了大量的资料,但是没有找到最终的解决方案,一般都是要求修改协议,加上对小包的ACK处理,但我们这边无法控制服务器。
我们也试着控制KeepAlive和NoDelay,但还是没效果:
//对sock_cli设置KEEPALIVE和NODELAY
len = sizeof(unsigned int);
setsockopt(sock_cli, SOL_SOCKET, SO_KEEPALIVE, &optval, len);//使用KEEPALIVE
setsockopt(sock_cli, IPPROTO_TCP, TCP_NODELAY, &optval, len);//禁用NAGLE算法

请问有什么方式可以解决这种情况?
先谢谢了。
...全文
342 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
cceczjxy 2010-04-12
  • 打赏
  • 举报
回复
这个应该是你的无线网络协议栈的问题.
Kingron 2010-04-12
  • 打赏
  • 举报
回复
还是比较痛苦……,即使缓冲最后一个小包,如果TCP/IP协议栈底层拼了一个半小包丢了,就不好处理了。
ronliu 2010-04-01
  • 打赏
  • 举报
回复
主要的思路是检测失败并重传。一种是服务器主动确认,另一种是在客户端上检测是否发送成功。
千里孤行的ioctl(tcp_socket, SIOCOUTQ, &value),应该行得通。赞!
Kingron 2010-03-31
  • 打赏
  • 举报
回复
多谢千里孤行的指点,我们试试看,也期待其他的解决方法。
yanghehong 2010-03-16
  • 打赏
  • 举报
回复
我上面说的设SO_SNDBUF在Linux上是不行的。Linux不让把发送buffer设为0,不管你设多小,最小都为2048.


所以,如果是Linux上的,可以试试换个思路。
既然发送失败(有残留没发送出去)已经不可避免,那么就承认这个失败。在这种情况下,客户端要多做一步,找出这些残留有多少。

使用
ioctl(tcp_socket, SIOCOUTQ, &value);
可以得到TCP socket发送队列里头还没有发送出去的数据有多少。

如果不为0,那么证明你最后一次发送是没有成功的,尽管写入buffer成功。这时你的客户端程序就显示失败就可以了。


- 千里孤行
yanghehong 2010-03-16
  • 打赏
  • 举报
回复
你做的是linux上的客户端?
如果是Windows的,可以把内核的发送buffer设为0,也就是socket的SO_SNDBUF选项。那么直到服务器TCP收到数据并ack了,客户端的写入才返回成功。



- 千里孤行
Kingron 2010-03-16
  • 打赏
  • 举报
回复
有没有办法在第二步的时候,select是否发送成功?或者Flush一下Socket Buffer?
找了一下这个方面,也没有相关资料。
soclays 2010-03-16
  • 打赏
  • 举报
回复
这没办法了,要纠错和重传的话等于你得自己实现层应用层协议
肯定得协议双方配合啊
改不了服务端就没办法了

23,217

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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