Erlang与Flash的Socket通讯-03

本文介绍了在网络编程中遇到的“粘包”问题及其解决方案。粘包现象发生在数据发送端连续发送的数据包因网络特性而连贯在一起,导致接收端无法区分各数据包。文中详细解释了两种防止粘包的方法,并提供了Flash客户端与Erlang服务端配合使用的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天和阿灿为项目做一个多人在线行走的Demo,在Flash端遇到数据“粘包”的问题,下面记录一下原理和处理办法。


什么是“粘包”呢?粘包是指数据发送端希望接受端收到的数据包因为网络的“流”特性,使得连续的数据包的字节连贯在一起,导致接收端无法以数据包为单位处理数据的情况。

打个比方吧,A和B两个人通过一根水管互相传递水,他们通过每次接到的水的重量来判断对方表达的意思。如果A连续乘了不同重量的几杯水倒入水管中传递给B,B那一头打开水龙头接到的只能是连贯的水流,而不是一杯杯的水,数据在网络上传递也是同样道理,数据是以流的方式传递的,通讯双方需要通过一定的协议来分割数据流。

防止粘包的典型处理方式有两种,一种是通过判断结束符来分割数据包,这种方式就得确保分隔符不会出现在数据包的主体中,有一定的局限性;另一种是通过在数据包的开始部分加上固定字节长度的一个头部,用以表示数据包的长度。

Erlang天生就具备了解析数据包长度的功能,通过设置socket的{packet, 2}属性,Erlang会在接收到数据时会自动按数据的头两个字节表示的短整型值来分割数据包,所以在Erlang端没有粘包问题。但是在Flash端如果惯性思维的以为数据包会分次到达并分别触发SocketData事件那就会出问题了,由于网络的不可靠性,一个数据包有可能在触发N次SocketData事件后才完整接收完毕,也可能一次SocketData事件接收到的数据包含连续多个数据包,甚至尾部有可能包含最后一个数据包的起始部分但又不完整。

之前的实验有证明了Flash端通过writeUTF函数可以跟Erlang的{packet, 2}模式对应,但是这种方式只能传递字符串,当需要传递二进制数据的时候就只能靠自己拆包和解包了。下面是与Erlang的{packet, 2}模式对应的Flash客户端接收数据的代码:
private static var packet_len : int;
private static var packet_buf : ByteArray;

private static function OnSocketData (event:ProgressEvent) : void
{
    while (socket.bytesAvailable > 0)
    {
        if (packet_len == -1)
        {
            if (socket.bytesAvailable < 2)
                break;

            packet_len = socket.readShort();

            packet_buf = new ByteArray();
        }

        socket.readBytes(packet_buf, 0, packet_len - packet_buf.length);

        if (packet_buf.length == packet_len)
        {
            ParsePacket(packet_buf);

            packet_len = -1;
        }
    }
}

数据会被暂存到packet_buf中,直到packet_buf中数据达到预期的数据包大小,才将packet_buf传递给ParsePacket进行解析,否则,如果socket还有可读数据就尝试读取数据包剩余的数据,如果没有则等待下次SocketData事件。

错误:软件包:rabbitmq-server-3.13.7-1.el8.noarch (rabbitmq_server) 需要:erlang >= 26.0 已安装: erlang-23.3.4.11-1.el7.x86_64 (@rabbitmq-erlang) erlang = 23.3.4.11-1.el7 可用: erlang-R16B-03.18.el7.x86_64 (epel) erlang = R16B-03.18.el7 可用: erlang-20.3.8.25-1.el7.x86_64 (rabbitmq-erlang) erlang = 20.3.8.25-1.el7 可用: erlang-20.3.8.26-1.el7.x86_64 (rabbitmq-erlang) erlang = 20.3.8.26-1.el7 可用: erlang-21.3.8.14-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.14-1.el7 可用: erlang-21.3.8.15-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.15-1.el7 可用: erlang-21.3.8.16-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.16-1.el7 可用: erlang-21.3.8.18-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.18-1.el7 可用: erlang-21.3.8.21-1.el7.x86_64 (rabbitmq-erlang) erlang = 21.3.8.21-1.el7 可用: erlang-22.2.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.2.7-1.el7 可用: erlang-22.2.8-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.2.8-1.el7 可用: erlang-22.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3-1.el7 可用: erlang-22.3.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.1-1.el7 可用: erlang-22.3.2-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.2-1.el7 可用: erlang-22.3.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.3-1.el7 可用: erlang-22.3.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4-1.el7 可用: erlang-22.3.4.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.7-1.el7 可用: erlang-22.3.4.10-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.10-1.el7 可用: erlang-22.3.4.11-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.11-1.el7 可用: erlang-22.3.4.12-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.12-1.el7 可用: erlang-22.3.4.16-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.16-1.el7 可用: erlang-22.3.4.19-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.19-1.el7 可用: erlang-22.3.4.21-1.el7.x86_64 (rabbitmq-erlang) erlang = 22.3.4.21-1.el7 可用: erlang-23.1.2-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.1.2-1.el7 可用: erlang-23.1.5-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.1.5-1.el7 可用: erlang-23.2.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.1-1.el7 可用: erlang-23.2.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.3-1.el7 可用: erlang-23.2.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.4-1.el7 可用: erlang-23.2.5-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.5-1.el7 可用: erlang-23.2.6-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.6-1.el7 可用: erlang-23.2.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.7-1.el7 可用: erlang-23.2.7-2.el7.x86_64 (rabbitmq-erlang) erlang = 23.2.7-2.el7 可用: erlang-23.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3-1.el7 可用: erlang-23.3-2.el7.x86_64 (rabbitmq-erlang) erlang = 23.3-2.el7 可用: erlang-23.3.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.1-1.el7 可用: erlang-23.3.2-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.2-1.el7 可用: erlang-23.3.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.3-1.el7 可用: erlang-23.3.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4-1.el7 可用: erlang-23.3.4.1-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.1-1.el7 可用: erlang-23.3.4.3-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.3-1.el7 可用: erlang-23.3.4.4-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.4-1.el7 可用: erlang-23.3.4.5-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.5-1.el7 可用: erlang-23.3.4.6-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.6-1.el7 可用: erlang-23.3.4.7-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.7-1.el7 可用: erlang-23.3.4.8-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.8-1.el7 可用: erlang-23.3.4.10-1.el7.x86_64 (rabbitmq-erlang) erlang = 23.3.4.10-1.el7 您可以尝试添加 --skip-broken 选项来解决该问题 您可以尝试执行:rpm -Va --nofiles --nodigest
07-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值