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. poj 3311 Hie with the Pie(状态压缩dp)

    Description The Pizazz Pizzeria prides itself or more (up to ) orders to be processed before he star ...

  2. ubuntu 步步为营之uclinux编译和移植(完整版)

    本节主要包含(ubuntu10.04) 一,linux下的经常使用压缩解压缩命令 二,环境建立 三,内核编译 四,移植 一,linux下的经常使用压缩解压缩命令 在linux下常见的压缩文件格式有ta ...

  3. nand烧写分析/内核在启动过程中式如何将这个文件映射成/目录及各子目录的?

    我用的是ramdisk.image.gz,烧写在flash的0x10140000处 我不太明白内核在启动过程中式如何将这个文件映射成/目录及各子目录的? 如果ramdisk.image.gz在flas ...

  4. (续)检测到有潜在危险的 Request.Form 值

    继续昨天的问题“检测到有潜在危险的 Request.Form 值”,前面说如果不想取消数据验证那怎么避免这个问题. 既然是数据验证到危险值然后报错那么我们可不可以在验证的中间做一个处理让他不报错,比如 ...

  5. Bootstrap的datepicker控件

    为input 控件的text 添加datepicker()方法后,原本的控件change事件无法正常触发.原因是项目中同时使用了用了jquery ui,碰巧它里面也有一个datepicker,名字一模 ...

  6. python 使用 tweepy 案例: PS4

    First, make sure Python and Tweepy installed well, and the network setup well. Then, you go to http: ...

  7. autoresizing代码实现

    主要解决父子控件之间的布局关系: /*     Flexible 灵活的,自由的          typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) ...

  8. C# Cache何时使用及使用方法

    Cache 即高速缓存.那么cache是怎么样提高系统性能与运行速度呢?是不是在任何情况下用cache都能提高性能?是不是cache用的越多就越好呢?我在近 期开发的项目中有所体会,写下来当作总结也希 ...

  9. java web 之 WebRoot和WebContent目录

    WebRoot和WebContent都是程序的根文件夹,无本质区别,一下是两者的共同点和不同点: 共同点:都有一个WEB-INF文件夹,其下文件不可直接访问: WEB-INF是安全目录,所谓安全,就是 ...

  10. Emgu学习笔记(一)安装及运行Sample

    1.简单说明 Emgu是Dot Net平台对OpenCV的封装,本质上没有增加新功能,是通过Dot Net的平台调用技术直接调用OpenCV C++语言写的库,使用我们可以方便用.net平台通过Ope ...