`

MINA和AS3的socket接收问题

阅读更多

关于粘包问题,到网上找了一下,发现解决方法其实很多:

 

AMF3

http://www.klstudio.com/post/202.html

 

MINA自带的sumup例子

http://mina.apache.org/documentation.html

 

Apache SSHD

http://mina.apache.org/sshd/

 

L potato中讨论AS3出现的粘包问题

http://code.google.com/p/lpotato/source/browse/trunk/java/toolkit/WebContent/test/flash/SocketBridge.as?r=13

 

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在

http://opensource.adobe.com/svn/opensource/flex/sdk/trunk/modules/debugger/src/java/flash/tools/debugger/concrete/DProtocol.java

 

 

使用早期的同步机制(好像没有用并发库和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(类成员)截断以保留不完整的收包。

另外,还使用命令队列,包括空闲和激活队列。

 

待考

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

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics