AS3.0中使用Socket使用tcp服务器协议,它是一种流协议,不停的将分片传输给客户端,P作为流,发包是不会整包到达的,而是源源不断的。
它不同于UDP服务器协议,UDP作为数据包协议,整包到达。 如果要使用Socket接收数据我们必须使用ProgressEvent.SOCKET_DATA事件。这个事件在帮助文档中是这样描述的 ——在套接字接收到数据后调度。
而事实却并非如此,做过一次尝试,服务器发送了20000次数据而rogressEvent.SOCKET_DATA事件只产生了2000多次。
那么为什么说"服务器发送了20000次数据而rogressEvent.SOCKET_DATA事件只产生了2000多次",
因为flash socket使用的TCP/IP协议, 这个协议跟UDP不同,它不是以单个"包"的形式发送数据,它发送的是"流数据",所以即便你发来20000次数据(也就是你所想象的20000个包),TCP协议也是将它视作"流"发送.
换句话说,你的20000次数据,实际上只被分割成了2000多个"包"来发送,因此socket收到了2000多个包,,因此只产生了2000多次的事件.
另外,如果as3 的data事件函数正在执行的时候,比如在此函数中用while循环解码,此时有新的数据发送过来,data事件还会触发么?触发的话,正在执行的怎么办?原有数据还有么?
答案是会触发的,所以将socket数据read的时候,必须做一个循环 while,每到一个包刚好读取完成的时候(包头用一个整型记录完整包的长度。每次都先读取一个包长度,然后按照包长度读取指定长度的数据作为一个完整数 据包传递到到逻辑层),又继续读取下一个包,然后把解码后的每个包都放进一个数组里面依次读取。还有一点要注意的是 socket.bytesAvailable长度是每read一次就减去所读的长度,直至读取完毕,最后为0;此处的bytesAvailable如果重 新设置position为0,那该数组的bytesAvailable又是满的。
附一下代码进行研究:
view plaincopy to clipboardprint?
private function Net_Data(evt:ProgressEvent):void
{
var ba:ByteArray = new ByteArray();//创建一个
socket.readBytes(ba, 0, evt.bytesTotal); //服务器一次性发送的总共的数据,可能是几个包,也可能是几个半包
packetBuffer.push(ba); //把ba放入缓冲区,其实就是把ba放入packetBuffer类中的一个ByteArray对象里
var packets:Array = packetBuffer.getPackets(); //这里就是在进行解码(包含循环)
for each(var packet:MsgPacket in packets)
{
dispatch(packet); //对解码后的数据进行处理,可以说是直接使用、赋值
}
}
private function Net_Data(evt:ProgressEvent):void { var ba:ByteArray = new ByteArray();//创建一个 socket.readBytes(ba, 0, evt.bytesTotal); //服务器一次性发送的总共的数据,可能是几个包,也可能是几个半包 packetBuffer.push(ba); //把ba放入缓冲区,其实就是把ba放入packetBuffer类中的一个ByteArray对象里 var packets:Array = packetBuffer.getPackets(); //这里就是在进行解码(包含循环) for each(var packet:MsgPacket in packets) { dispatch(packet); //对解码后的数据进行处理,可以说是直接使用、赋值 } } packetBuffer.as
view plaincopy to clipboardprint?
package org.green.server.data
{
import flash.utils.ByteArray; public class PacketBuffer
{
private var buf:ByteArray = new ByteArray();
private static const SPLIT:int = 21316;// "DS"
public function PacketBuffer()
{
}
public function push(ba:ByteArray):void
{
if(buf == null)
{
buf = ba;
}else
{
buf.position = buf.length;
buf.writeBytes(ba);
}
}
public function getPackets():Array
{
var ps:Array = [];
var ptr:uint = 0;
buf.position = ptr;
while(buf.bytesAvailable >= 2) //这里是说当可用数据大于包头时,一个包==包头(body的长度)+包体(body),也就是说包里如果一旦有数据就开始执行
{ //2其实是readShort()后,少了的2个字节,也就是body有数据的时候才开始解码
var len:uint = buf.readShort();
//不足一个包,这里完全有可能,当只读取完包头len,但是body却没有读取到末尾
if(buf.bytesAvailable < len)
{
var ba:ByteArray = MsgUtil.createByteArray();
buf.position = ptr;
ba.writeBytes(buf, 0, buf.bytesAvailable);
buf = ba;
//返回
return ps;
}
buf.position = 2;
var mb:ByteArray = new ByteArray();
buf.readBytes(mb, 0, len); //len为body的长度,将body的数据放入mb
mb.position = 0;
var msg:MsgPacket = MsgUtil.createMsgPacket(mb,magic);//这里在对body解码过程 略
buf.position=0;
ps.push(msg); //放入数组
//下一个包 while语句进行下一个循环
}
if(buf.bytesAvailable <= 0)buf = null;
return ps;
}
public function clear():void
{
buf=null;
}
}
} as3 socket test
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.external.ExternalInterface;
import flash.net.Socket;
public class receiveData extends Sprite
{
public function receiveData()
{
trace(ProgressEvent.SOCKET_DATA);
socket.connect("127.0.0.1", 4300);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onServerData,false,0,true);
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(Event.CLOSE, closeHandler);
socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
private var socket:Socket=new Socket();
private var msg:String = "";
private function onServerData(event:ProgressEvent):void{
if(socket.bytesAvailable){
msg = socket.readUTFBytes(socket.bytesAvailable);
trace(msg);
ExternalInterface.call("window.jsFunc", msg);
}
}
private function connectHandler(event:Event):void{
trace("connected");
}
private function closeHandler(event:Event):void{
trace("closed");
clearHandler();
}
private function ioErrorHandler(event:IOErrorEvent):void{
//to do
clearHandler();
}
private function clearHandler():void{
socket.removeEventListener(ProgressEvent.SOCKET_DATA, connectHandler);
socket.removeEventListener(Event.CONNECT, connectHandler);
socket.removeEventListener(Event.CLOSE, closeHandler);
socket.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
}
}

AS3: Socket 数据包 收 发的更多相关文章

  1. C# 实现的多线程异步Socket数据包接收器框架

    转载自Csdn : http://blog.csdn.net/jubao_liang/article/details/4005438 几天前在博问中看到一个C# Socket问题,就想到笔者2004年 ...

  2. Java nio socket与as3 socket(粘包解码)连接的应用实例

    对Java nio socket与as3 socket连接的简单应用 <ignore_js_op>Java nio socket与as3 socket连接的应用实例.rar (9.61 K ...

  3. Socket 数据包顺序的问题

    今天遇到一个问题,到现在还未查明原因,记录一下,留后续跟踪. 基于Netty的Socket通讯问题,Server在向Client发送数据时,假设数据原顺序为1,2,3,4...  但到了客户端顺序可能 ...

  4. 数据包从物理网卡流经 Open vSwitch 进入 OpenStack 云主机的流程

    目录 文章目录 目录 前言 数据包从物理网卡进入虚拟机的流程 物理网卡处理 如何将网卡收到的数据写入到内核内存? 中断下半部分软中断处理 数据包在内核态 OvS Bridge(Datapath)中的处 ...

  5. Tcp/Ip协议族简单解读及网络数据包/报/帧数据格式及封装及解包;

    http://www.creseek.cn/products-install/install_on_bsd_linux/ 中文检索 离线cloudera ecosystem components: h ...

  6. 数据包接收系列 — IP协议处理流程(二)

    本文主要内容:在接收数据包时,IP协议的处理流程. 内核版本:2.6.37 Author:zhangskd @ csdn blog 我们接着来看数据包如何发往本地的四层协议. ip_local_del ...

  7. Linux网络 - 数据包的接收过程【转】

    转自:https://segmentfault.com/a/1190000008836467 本文将介绍在Linux系统中,数据包是如何一步一步从网卡传到进程手中的. 如果英文没有问题,强烈建议阅读后 ...

  8. Linux 中的网络数据包捕获

    Linux 中的网络数据包捕获 Ashish Chaurasia, 工程师 简介: 本教程介绍了捕获和操纵数据包的不同机制.安全应用程序,如 VPN.防火墙和嗅探器,以及网络应用程序,如路由程序,都依 ...

  9. 基于TILE-GX实现快速数据包处理框架-netlib实现分析【转】

    最近在研究suricata源码,在匹配模式的时候,有tilegx mpipe mode,转载下文,了解一下. 原文地址:http://blog.csdn.net/lhl_blog/article/de ...

随机推荐

  1. 【LeetCode练习题】Reverse Words in a String

    Reverse Words in a String Given an input string, reverse the string word by word. For example,Given ...

  2. centos directory server

    http://www.aliyun.com/zixun/content/3_12_517262.html CentOS系统安装Directory Server 8.1操作方法 发布时间:2014-12 ...

  3. SVN:冲突解决 合并别人的修改

    在项目中,基本不可避免多个人同时参与一个项目,因此就可能会出现多个人同时修改一个文件的情况,就不可避免的会出现冲突.svn已经很聪明了,如 果你和别人对于同一个文件的修改之间不存在重叠(比如你在文件最 ...

  4. wxpython StatuBar 带进度条的状态栏

    # -*- coding: utf- -*- import wx class customStatusBar(wx.StatusBar): def __init__(self, parent): wx ...

  5. ios7 UITableView底线右移

    在ios7上UITableView底线右移了,我们可以通过添加代码来让它铺满整个屏幕的宽,在使用前要加上判断是否有这个方法 if ([_tableView respondsToSelector:@se ...

  6. LightOJ 1338 && 1387 - Setu && LightOJ 1433 && CodeForces 246B(水题)

    B - B Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status P ...

  7. 淘宝弹性布局方案lib-flexible研究

    1. lib-flexible不能与响应式布局兼容 先说说响应式布局的一些基本认识: 响应式布局的表现是:网页通过css媒介查询判断可视区域的宽度,在不同的范围应用不同的样式,以便在不同尺寸的设备上呈 ...

  8. Java - 反射机制(Reflection)

    Java - 反射机制(Reflection)     > Reflection 是被视为 动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的       ...

  9. JAVA HashMap与HashTable 区别

    HashTable和HashMap区别 第一,继承不同. public class Hashtable extends Dictionary implements Mappublic class Ha ...

  10. live555从RTSP服务器读取数据到使用接收到的数据流程分析

    本文在linux环境下编译live555工程,并用cgdb调试工具对live555工程中的testProgs目录下的openRTSP的执行过程进行了跟踪分析,直到将从socket端读取视频数据并保存为 ...