AS3 TCP Socket 拆包

AS3 TCP Socket 拆包


在 AS3 中的 Socket 只有 TCP 一种方式,而 TCP 就必然面临拆包的问题。对于 Windows、Linux、Mac等操作系统的不同网络模型,Flash 程序在不拆包下的运行糟糕程度不一样,我的亲身体会是 Windows 的网络模型会积攒更大的缓冲区数据让 Flash TCP Socket 每次收到的数据量都比 Mac 上的多,所以情况就更糟糕。这时候拆包的效果就十分明显。

下面有一段更形象化的解释,摘自 Netty 的


One Small Caveat of Socket Buffer

In a stream-based transport such as TCP/IP, received data is stored into a socket
receive buffer. Unfortunately, the buffer of a stream-based transport is not a queue of
packets but a queue of bytes. It means, even if you sent two messages as two independent
packets, an operating system will not treat them as two messages but as just a bunch of
bytes. Therefore, there is no guarantee that what you read is exactly what your remote
peer wrote. For example, let us assume that the TCP/IP stack of an operating system has
received three packets:

+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+

Because of this general property of a stream-based protocol, there's high chance of reading them in the following fragmented form in your application:

+----+-------+---+---+
| AB | CDEFG | H | I |
+----+-------+---+---+

Therefore, a receiving part, regardless it is server-side or client-side, should defrag the
received data into one or more meaningful frames that could be easily understood by the
application logic. In case of the example above, the received data should be framed like the
following:

+-----+-----+-----+
| ABC | DEF | GHI |
+-----+-----+-----+

下面实例中的 _socket 和 lastReservedLength 都是在函数外部定义的,其定义不影响程序的理解。各段含义我写在了程序的注释中。

部分代码如下:


private function onResponse(e:ProgressEvent):void
{
    // Data available from socket
    while (_socket.bytesAvailable > 0)
    {
        var tmpLength:int = 0;
        
        // Last package received is incomplete, and package length maintains last reserved length
        if (lastReservedLength > 0)
        {
            // CASE 1: Package is still incomplete after receiving data from socket at least once
            if (lastReservedLength > _socket.bytesAvailable + 4) break;
                
                // CASE 2: The last part of a package
            else tmpLength = lastReservedLength;
        }
            // Last package received is complete, and package length should be read from socket 
        else
        {
            var lengthBytes:ByteArray = new ByteArray();
            lengthBytes.endian = Endian.LITTLE_ENDIAN;
            
            _socket.readBytes(lengthBytes, 0, 4); // TODO Crash!
            //Error: Error #2030: End of file was encountered.
            //at flash.net::Socket/readBytes()
            
            tmpLength = lengthBytes.readInt();
            
            // CASE 3: The first part of a package
            if (_socket.bytesAvailable < tmpLength - 4)
            {
                lastReservedLength = tmpLength;
                break;
            }
        }
        
        // CASE 4: A complete package received once
        
        // Generate ByteArray of a complete package
        var resultBytes:ByteArray = new ByteArray();
        resultBytes.writeInt(tmpLength);
        _socket.readBytes(resultBytes, 4, tmpLength - 4);
        lastReservedLength = 0;
        
        // parse the ByteArray
        resultBytes.position = 0;
        var resProto:Object = CppLibUtil.parseMediaProto(resultBytes);
        
        // Dispatch the ByteArray
        if (resProto != null) {
            
            var uri:String;
            
            try {
                uri = resProto.uri;
            } catch (e:Event) {
                trace(e);
            }
                
            dispatchEvent(new InternalEvent(uri, resProto));
        }
    }
}

-

转载请注明来自柳大的CSDN博客:Blog.CSDN.net/Poechant,微博:weibo.com/lauginhom

-

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟超

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值