关于粘包问题,到网上找了一下,发现解决方法其实很多:
AMF3
http://www.klstudio.com/post/202.html
MINA自带的sumup例子
http://mina.apache.org/documentation.html
Apache SSHD
L potato中讨论AS3出现的粘包问题
hudo实现sgs客户端时处理ProgressEvent.SOCKET_DATA事件的方法
http://code.google.com/p/hudo/
darkstar-as3也处理过类似的问题,不过方法略有不同,似乎叫payload(意思叫有效载荷)
http://code.google.com/p/darkstar-as3/
总而言之,处理二进制流数据时不写循环是不严谨的,由于naggle算法的影响
http://zh.wikipedia.org/zh-cn/%E7%B4%8D%E6%A0%BC%E7%AE%97%E6%B3%95
网速会导致数据包的大小是无法预计的,因此读数据算法需要慎重考虑(尤其是非文本协议)。
MINA和AS3存在类似的问题,你可以延迟读出和连续读出,维护一个状态值,但基于性能问题,
最好不要在这方面使用耗时的操作——MINA的receive会阻塞会话,而flash也会阻塞enterFrame。
方法其实还有很多,例如使用分界字符。NIO使socket和线程不再是一对一而是一对多,而flash的异步网络读写更是让人耳目一新,觉得自己要熟练掌握这些技术还需要付出更大的努力。
-------------------------------------------------
20100720 update:
* 使用base64,直接用文本模式通信(服务器和客户端需要做base64的编解码)
可以参考f3server的代码
http://code.google.com/p/f3server/
按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
代价:数据量大了,只能防君子。
好处:用文本传输任意二进制数据,不再限于文本。
f3server没有添加ssl的支持(估计很想这么做),如果程序开发者觉得安全不重要,可以考虑用这种base64的方法避开mina的粘包问题。(题外话——我对base64和字符串操作没信心,对于正则表达式完全是白痴,还是用纯二进制传输好了,虽然写mina的自定义协议很让人抓狂)
-------------------------------------------------
20100819 update:
如果你对客户端数据解析有复杂需求,并且需要实时处理,可以参考《Actionscript 3.0宝典》介绍的一个开源项目的代码。
FVNC
http://code.google.com/p/fvnc/
这是一个远程桌面的flash客户端。
它实现数据接收队列和循环协议解析。
由于实现得过于繁琐而且考虑大数据传输,
个人认为这不是一种实用的解决方法。
但如果对数据结构有高级别的认识(我级别还不够高= =b)可以考虑用svn下载这份代码。
另外,它对网络协议层的封装方法也比较规范和标准。
-------------------------------------------------
20100830 update:
as3chat
http://code.google.com/p/as3chat/
客户端as中接收与发送数据,貌似是socket+xml,但不太明白为什么不直接使用xmlsocket?
--------------------------------------------------
20101013 update:
还发现一个写得很规范的AS3库,用于解析sgs的pack格式socket数据包:
yadaa (Yet Another Darkstar ActionScript API)
http://code.google.com/p/yadaa/
收数据的关键代码在com.plamentotev.yadaa.client.PDSClient
的processServerMessage()
和onData监听器中,
特点是使用while轮询消除粘包。
使用Logger记录日志,
使用if(this.dataBuffer.bytesAvailable < msgSize)和倒退position延迟处理实现包的合并。
processServerMessage()只能获得包的复制内存。
每次轮询读包后总是要分配新的ByteArray,即使还有剩余数据,也要转移到新的ByteArray。
----------------------------------------------
20110130 update
Adobe Flex SDK的fdb调试器
svn在
使用早期的同步机制(好像没有用并发库和ByteBuffer),使用循环消除分裂的接收包。
使用包长度和命令整数机制。
使用小对象缓存(用不同长度byte[]的DMessage缓存不同长度的收包)。
(有些书认为在Java中没必要使用池,只对于创建代价太高的对象如线程、数据库连接才应该使用池。
他们认为池阻碍Java虚拟机执行GC,因为池内的对象因为引用而不会被GC。
另一方面,他们认为Java虚拟机本身就有机制可以防止内存碎片和快速分配释放内存,没必要手工做这样的事情。
所以我觉得最好自己实测一下)
----------------------------------------------
20110228 update:
rpggamelib:
在ProgressEvent.SOCKET_DATA事件句柄中循环读socket以消除粘包
http://code.google.com/p/rpggamelib/
http://rpggamelib.googlecode.com/svn/trunk/net/rpg/core/net/NetPack.as
-----------------------------------------------
20110320 update:
as3redis:
https://github.com/claus/as3redis
我不是太了解包的结构,但是可以看到Redis.as文件中的监听器
protected function dataHandler(e:ProgressEvent):void
中使用while消除分裂包,
使用commandProcessed布尔变量等待下一次接收,
最后的长度判断用于把持久的状态值buffer(类成员)截断以保留不完整的收包。
另外,还使用命令队列,包括空闲和激活队列。
待考
-----------------------------------------------