您现在的位置: 365建站网 > 365文章 > TCP读取报文不完整的问题分析

TCP读取报文不完整的问题分析

文章来源:365jz.com     点击数:674    更新时间:2009-10-24 08:40   参与评论

首先解释一下这个题目, "报文"指的是业务层自定义的报文, TCP是流式协议, 不像UDP那样是报文协议.

某两个系统间进行网络交互, 请求报文的格式为:

<json串>&sig=xxx

SYS-ATM作为请求方, 用PHP的stream_socket_sendto()进行发送. SYS-SIM开发服务器端, 使用Python的twisted框架. 上线后, 出现问题, 服务器端接收到的报文不完整. 例如, json串只读了一半, 或者缺少"&sig=xxx", 缺少的数据是随机的, 但只缺少尾部, 已经接收到数据没有差错.

发送方代码:

$str = sprintf('json=%s&sig=%s', $json, $sig);
stream_socket_sendto($fp, $str);

接收方代码:

class XServer(Protocol):
def dataReceived(self, data):
#处理一个报文

factory = Factory()
factory.protocol = XServer
reactor.listenTCP(19009, factory)
reactor.run()

我们通过PHP和Python的API文档, 以及我们对网络协议和套接口的理解来分析.

问题1: 发送缓冲太小了吗?(发送方分包了吗?)

我们首先想到的原因会不会是, 发送方的发送缓冲比一个报文小, 所以"分包"了? 不过仔细一想, 这个问题出发点本身就是错误的. 因为TCP协议是流式协议, 不存在"分包"的问题, 因为TCP只能看到字节流, 不认识报文(包). 所以, 发送方的发送缓冲大小不影响接收.

问题2: 接收缓冲太小了吗?

怀疑完发送缓冲, 现在来怀疑一下接收缓冲. 因为使用的是TCP协议, 所以, 就算是只读到一个字节的数据, dataReceived()也可能被调用一次, 所以, 在dataReceived()中把接收到的数据当作一个报文, 就犯了逻辑错误, 与接收缓冲的大小无关. 而且, dataReceived()的API文档提到: Please keep in mind that you will probably need to buffer some data.

问题1和问题2都有相同的错误, 那就是错误地把TCP当作是基于报文的协议. 使用TCP, 如果应用层协议不是基于报文的, 你可以在每一次读数据之后对数据进行处理, 比如, echo程序. 如果应用层协议是基于报文的, 那么, 你必须自己组装报文; 或者, 一次TCP会话只发送一个报文, 通过连接关闭来显示声明报文发送完毕. 而一个报文可能需要多次读操作才能组装完毕, 也可能一次读包含了多于一个报文(如果不是停止等待应答的话).

结论:

1. 重新定义报文格式, 基于行的协议

基于TCP socket的程序, 有几种方式可用来实现报文协议:

1. 报文中声明报文数据的长度.
2. 使用分隔符.
3. 发送方发送完一个报文后关闭连接.

业务层本意上是想使用一种基于报文的协议, 但所定义的报文格式并没有提供报文分隔符或者长度字段, 这就要求程序进行语义分析, 增加了实现难度. 现在改成使用换行符作为分隔符.

2. 改写接收端代码, 使用基于行的接口

class XServer(LineServer):
def lineReceived(self, data):
#处理一个报文

前面提到, 我们必须自己组装报文, 但这不代表我们要自己写组装代码, 行IO库可以替我们做这项工作. LineServer实现了基于行的协议, 只有读到完整的一行, lineReceived()才会调用.

姊妹篇: 编写基于TCP的应用程序 http://www.ideawu.net/blog/?p=429

你现在看的文章是: TCP读取报文不完整的问题分析  

如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛

发表评论 (674人查看0条评论)
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
昵称:
最新评论
------分隔线----------------------------

快速入口

· 365软件
· 杰创官网
· 建站工具
· 网站大全

其它栏目

· 建站教程
· 365学习

业务咨询

· 技术支持
· 服务时间:9:00-18:00
365建站网二维码

Powered by 365建站网 RSS地图 HTML地图

copyright © 2013-2024 版权所有 鄂ICP备17013400号