`

【转载+原创】Flash 接收 Socket 数据包

阅读更多

最近要写一个c++和flash通过tcp通信的程序, 遇到了不少的麻烦, 最后是解决了, 现把解决方法记录一下

需要解决的问题就是使用C++通过本地tcp连接向flash程序单向循环发送字符串, 遇到的问题就是在flash端接收的时候发现明明在C++端分好几次send的数据, 在flash一端的回调却只会调用一次。

 

转载自:http://cjmxp007.blog.163.com/blog/static/35473837201061054116916/

 

AS3.0 中使用Socket使用 tcp服务器协议,它是一种流协议,不停的将分片传输给客户端,作为流,发包是不会整包到达的,而是源源不断的。

它不同于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又是满的。

附一下代码进行研究:

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

 

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;
        }
    }
}

 

 

上文中使用的是一个缓存的技术解决了问题, 但是我不需要这么复杂, 最后, 我是这样解决问题的:

 

package 
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.net.Socket;


	/**
	 * ...
	 * @author 
	 */
	
	public class get_udp extends MovieClip 
	{
		var RFIDSocket:Socket;
		var receive_buffer:String="";
		var comm_splitter:String = "\n";
		public function get_udp() 
		{
			init();
		}
		//var RFIDSocket:Socket;
		function init():void
		{
			RFIDSocket = new Socket("localhost",16000);

			RFIDSocket.addEventListener(ProgressEvent.SOCKET_DATA, socketData);
		}
		private function socketData(e:ProgressEvent):void
		{
            trace("收到的字节数"+RFIDSocket.bytesAvailable);
            while (RFIDSocket.bytesAvailable)  
            {
				// TODO: 进行优化, 一次读入多个字节, 检查是否含有回车, 然后进行截取
                var temp_char:String = RFIDSocket.readUTFBytes(1); 
				// 如果读入的是通信分割, 则进行处理
                if (temp_char == comm_splitter)
				{
					processKinectData(receive_buffer);
					receive_buffer = "";
				}else // 如果读入的是普通字符, 则存储
				{
					receive_buffer += temp_char;
				}
            }  
		}
		private function processKinectData(data:String):void
		{
			trace("处理Kinect数据:" + data);
		}

	}
}
 

 

-------------------------EOF----------------------

 

 

分享到:
评论

相关推荐

    (AS3)socket+客户端与服务端+实例

    而"socket"文件可能包含客户端代码或者是一个AS3项目文件,用于展示如何在Flash环境中建立Socket连接和发送/接收数据。 总结起来,这个主题涵盖了使用AS3的Socket进行客户端和服务端通信的基础知识,包括连接建立、...

    flash actionscript3游戏开发之as3的socket通信方式介绍即使用XMLSocket.zip

    在Flash ActionScript3游戏开发中,Socket通信是实现客户端与服务器之间实时互动的重要技术手段。本文将深入探讨AS3中的Socket通信方式,特别是利用XMLSocket进行网络交互的细节。 首先,XMLSocket是AS3中用于低级...

    java netty编写的socket tcp服务器+flash actionscript3编写的游戏客户端 C/S程序游戏源代码

    这是一个关于使用Java Netty构建TCP服务器以及Flash ActionScript3开发客户端的游戏C/S程序源代码的项目。这个项目展示了如何在服务器端使用Java Netty框架来处理网络通信,以及在客户端利用ActionScript3来实现游戏...

    AS3 SOCKET

    AS3中的SOCKET技术是ActionScript 3.0中用于实现网络通信的一种方式,它允许客户端(通常是Flash应用程序)与服务器之间进行低级的、基于TCP/IP协议的双向数据传输。在AS3中,有两种主要的类用于实现SOCKET通信:...

    UDP.rar_as3 udp_flash as3.0 UDP_flash发送udp_udp as3_windows as3.0

    在Flash Professional环境中打开FLA文件,我们可以看到相关的AS3代码和图形元素,这些代码可能是用来设置UDP连接,创建数据包,以及处理接收到的数据。 在AS3中实现UDP通信的步骤大致如下: 1. **初始化...

    flash+php文字聊天室

    它接收由Flash发送过来的数据包,通常包含用户名和消息内容,然后将这些信息存储在数据库中,以便后续查询和回放。同时,PHP还负责处理其他用户发送过来的消息,将新消息推送给所有在线用户。这通常通过轮询...

    C# Socket单端口多种通讯协议服务

    - **事件驱动编程**:Socket通信通常是基于事件的,如数据接收、连接建立和关闭等,因此需要理解和使用事件处理模型。 - **错误处理和异常安全**:网络通信可能会遇到各种异常,如连接中断、数据包损坏等,需要妥善...

    flex与java采用socket方式通信

    2. **ActionScript Socket类**:在Flex中,我们使用Flash的Socket类来建立与Java服务器的连接,通过open()方法指定服务器的IP地址和端口号,然后可以使用writeUTFBytes()和readUTF()等方法进行数据的读写。...

    Java Socket多人在线考试系统源程序

    "Java Socket多人在线考试系统演示.swf"则可能是系统的一个动态演示,通过Flash动画的形式展示系统的主要功能和操作流程,帮助用户快速理解和上手。 总的来说,这个Java Socket多人在线考试系统涉及到的知识点包括...

    [转] flex与c#基于socket的实时互动网络游戏编程教程一

    2. **C# Socket类**:学习C#中的System.Net.Sockets命名空间,特别是Socket类的用法,如创建Socket实例,绑定端口,监听连接,接受客户端请求,以及发送和接收数据的方法。 3. **Flex与Socket通信**:在Flex中,...

    PHP for Flash FMS源码

    2. **RTMP协议**:了解如何使用Flash Player与FMS通过RTMP协议进行数据交换,包括实时视频流、音频流和自定义数据包。 3. **AMF数据序列化**:AMF是一种高效的二进制数据格式,用于在Flash客户端和服务器之间交换...

    基于PHP的FLASHTXT 聊天室程序(新手学习).zip

    - 编写Flash客户端:使用ActionScript编程,创建用户界面,实现Socket连接,发送和接收数据。 - 数据库设计:通常,聊天室会涉及用户信息、聊天记录等数据存储,因此需要设计合理的数据库结构。 - 安全性考虑:在...

    flash as3 开心农场源代码

    1. **Socket或XMLSocket**:AS3提供了Socket和XMLSocket类用于实现客户端与服务器的双向通信,发送和接收游戏数据,如玩家动作、农场状态等。 2. **AMF(Action Message Format)**:通常用于Flash和服务器间的序列...

    as3-udp test

    这些资源可能涵盖了如何创建Socket对象、绑定端口、连接远程服务器、发送和接收数据的详细步骤,以及如何通过ANE实现UDP广播的指南。 总之,AS3虽然在UDP广播方面有所限制,但结合其他语言和ANE技术,开发者依然...

    librtmp长时间直播socket连接断开的原因

    在RTMP协议中,每个数据包都有一个时间戳,用于同步发送和接收的数据。在长时间的直播过程中,如果时间戳超过了32位整数的最大值(即2^32-1),就会出现“扩展时间戳”问题,导致时间戳回绕,可能引发连接中断。 ...

    Java和Flex交互常见问题及解决

    “粘包”是指在网络传输过程中,多个数据包被错误地合并成一个数据包的现象,这会导致接收方无法正确解析数据。 - **问题描述**:在Java与Flex之间进行Socket通信时,如果发送的数据量较大或者网络环境不稳定,就有...

    UDP.rar_UDP

    - `recvfrom()` 或 `read()` 函数:从网络接收UDP数据包,可以获取发送者的IP和端口信息。 6. LPC2400以太网控制器初始化: - 设置MAC地址:通过写入以太网控制器的特定寄存器,设置设备的物理MAC地址。 - IP...

    基于Socket的多核处理器测试系统.pdf

    文章详细描述了基于原始套接字的数据包处理机制,原始套接字允许程序员直接发送和接收网络层的数据包,从而绕过了操作系统的协议栈开销,这对于数据传输的效率至关重要。不仅如此,流媒体系统还集成了FFmpeg库来处理...

    wifi协议栈实现细节

    wifi 协议栈实现细节 ...wifi 协议栈的实现细节涉及到 STA 模式、AP 模式、WPA 加密协议、编译、cw1200 驱动程序、lwip 信息处理结构图、lwip 启动时序、宏编译开关、内存池、接收数据包和 API 函数调用等多个方面。

Global site tag (gtag.js) - Google Analytics