【原贴地址:http://blog.sina.com.cn/s/blog_538d55be01016uma.html 】
上次就领教过了,在socket的环境下编程,如果服务器端发包非常频繁,Flash会自动把几个包合并为一个
包接收。
所以必须人为的来区别每个包,而不能依赖ProgressEvent.SOCKET_DATA的事件触发。
因为一次事件触发可能包含了你的多个返回包。我的做法是在包前固定长度指明后面的包大小。
一直在MacOS的环境下开发,也没有问题。
今天在windows下准备投产Flash客户端却出问题了。
当服务器返回的包较大时(几十K), 在Mac下一切正常,在windows下客户端的数据却接受不全导致
数据混乱。
一开始我以为是服务端发送的包太大,就把发送改为拆包发送,每个包最大1024个字节。客户端收到
后自己组装。
最后证明不是这个原因。
经过反复查看数据包的记录,终于发现windows下Flash和Mac下的Flash的不同。
我们知道Flash的socket机制会把几个包合并为一个大包,引发一次Progress.SOCKET_DATA事件。
也就是说一次事件可能包含多个服务端发送的数据包。
但是,在windows下还有一种情况,当包特别频繁的到达时,还会把一个数据包分拆开,放到下一个
Progress.SOCKET_DATA里面。
比如:服务端发送了"ab", "cd", "ef"三个包,客户端可能会触发两次事件,socket里面分别包含了"abcde"和
"f"两个数据包。所以,如果只看第一个数据包,就会发现数据没有接受完整。必须等到下一个包到达时,才
能使用第三个数据包。
知道原因,就好办了。我的解决方案是:用一个Buffer来统一接受来自服务器的所有数据。根据每个包
前面的长度来取包内容。发现包内容的长度不够时,等到下一个数据包到达时再处理。
代码如下:
// Bytes Buffer private var readBuf:ByteArray = new ByteArray(); // offset记录readBuf的长度 private var offset:int = 0; // 需要等待后续包才能处理的数据的长度 private var pendingLen:int = 0; // Buffer目前读到的位置 private var read_pos:int = 0; // recv是ProgressEvent.SOCKET_DATA对应的处理函数 public function recv():void { // 首先把服务器发送的数据尽快接受完毕 while( socket.bytesAvailable > 0 ) { var bytesCount:int = socket.bytesAvailable; socket.readBytes(readBuf, offset, bytesCount); offset += bytesCount; } // 下面是对Buffer的处理 var len:int = 0; while( offset > read_pos ) { // 上个包还有数据没处理完,优先处理 if( pendingLen > 0 ) { withData(readBuf.readUTFBytes(pendingLen)); read_pos = read_pos + pendingLen + 10; pendingLen = 0; continue; } if( readBuf.bytesAvailable == 0 ) { break; } len = Number(readBuf.readUTFBytes(10)); // 判断Buffer里面的数据是否足够,如果不够,退出结束,等待后续的包解决。 if( len > readBuf.bytesAvailable ) { pendingLen = len; break; } else { withData(readBuf.readUTFBytes(len)); read_pos = read_pos + len + 10; } } // 表明无等待处理的数据,所有数据都已经被处理完了,可以清空Buffer了,等待后续包处理 if( pendingLen == 0 ) { readBuf.clear(); offset = 0; read_pos = 0; }
浙公网安备 33010602011771号