游戏开发中AS3和服务端通过socket通讯,如何处理粘包的问题
TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.
如下几种情况:
•A.数据完整,只有1个包。(正常)
•B.数据不全,半个包。(不正常)
•C.数据完整,多个包。(正常)
•D.B与C的结合,XX.x个数据包。(不正常)
原因:tcp底层会有一定的延迟合并一下数据包发送。这是流式数据包必定会出现的现象,在网络拥挤时,或者一次投递过多数据的时候非常容易出现。
所以普遍协议设计的手法是采用 HEAD+BODY的形式。
HEAD大多数包含一个完整意义的“协议包”的长度,通过该长度来校验当前获得的数据是否有半个包存在。如果有半个包,则不进行处理,等剩下的数据收到后再处理。
使用上述思想处理粘包问题的socket连接的主要代码如下:
1 private function socketDataHandler(event:ProgressEvent):void 2 { 3 var hander:IProxy 4 var module:uint ; 5 var method:uint ; 6 var data:Object ; 7 8 while (bytesAvailable >= 2 ) { //2字节长度, 9 if ( _dataLen == 0){ //之前没有读到数据长度 10 _dataLen = readUnsignedShort() ; 11 } 12 //其实这里还应该判断一下 _dataLen 是否大于2,不过如果小于2,应该是错误的协议了,判断了也多此一举 13 if ( bytesAvailable >= _dataLen ){ 14 module = readUnsignedByte() ; 15 method = readUnsignedByte() ; 16 //这里要读数据,不能因为没这模块就不读了 17 _cashBytes.clear() ; 18 readBytes( _cashBytes,0,_dataLen - 2 ) ; 19 _dataLen= 0 ; //代表这次的包已经读完了 20 //准备派发函数 21 hander = _handler[module]; 22 if (hander != null) 23 { 24 data = _pack.decode(_cashBytes); 25 // try { 26 hander.handleMessage(method,data); 27 // }catch (e : Error){ 28 29 // } 30 }else { 31 trace(module,"没有找到相关模块"); 32 } 33 } else { //半个包 34 break ; 35 } 36 } 37 }
注意:上述代码中的break,当检测到了包中数据不完整,出现半包现象时,跳出循环,等待收到剩下的数据后再进行处理。