导航

与MFC聊天服务器端配套的flex客户端

Posted on 2011-02-23 17:59  田园小蛙  阅读(459)  评论(0)    收藏  举报
  一个简单的聊天客户端,主要介绍flex如何与c++服务器端传递消息、解析消息。使用flash builder4和flex4.0开发。

  客户端提供连接服务器,发送和接收通讯消息(发送登陆消息,发送用户列表请求消息等)。

客户端运行后的界面:

解决方案:

一、客户端主逻辑

客户端的主逻辑都在“ChatClientFX.mxml”文件中实现。

“ChatClientFX.mxml”文件:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="570" minHeight="300" width="570" height="300" 
			   initialize="Init()">

	<fx:Script>
		<![CDATA[
			import flash.utils.Dictionary;
			
			import mx.collections.ArrayCollection;
			import mx.collections.ArrayList;
			import mx.events.FlexEvent;
			
			protected var _socketCon:SocketConnector;//网络连接
			
			private var _arrayRole:ArrayList = new ArrayList();//用户列表
			
			private var _strRoleName:String = "";//用户名
			private var _nRoleIndex:int = -1;//用户连接在服务器的索引
			private var _nReqRoleListMsgIndex:int = -1;//请求用户列表消息索引
			private var _dictRoles:Dictionary = new Dictionary();//存放收到的用户列表
			
			private function Init():void
			{
				_socketCon = new SocketConnector();
				
				_socketCon.addEventListener(ReceiveEvent.Event_NetMsg, OnReceiveEvent);
				
				var bhave:Boolean = _socketCon.hasEventListener(ReceiveEvent.Event_NetMsg);
				
				listRole.dataProvider = _arrayRole;
				
				_strRoleName = tbName.text;
				
				tbSend.addEventListener(FlexEvent.ENTER, OnEnterText);
			}
			
			private function OnEnterText(e:FlexEvent):void
			{
				SendText();
			}
			
			//处理接收到的消息
			private function OnReceiveEvent(e:ReceiveEvent):void
			{
				var netMsg:NetMsg = e.m_netMsg;
				
				if (netMsg == null)
					return;
				
				switch (netMsg.AbNetMsgHead.Type)
				{
					case EnumType.NetMsg_RoleEvent:
					{
						var nRoleIndex1:int = netMsg.GetIntValue("nRoleIndex");
						var strRoleName1:String = netMsg.GetStringValue("szRoleName");
						
						switch (netMsg.GetIntValue("nType"))
						{
							case EnumType.NetMsg_RoleEvent_ValideLogin:
							{
								
								_nRoleIndex = nRoleIndex1;
								_strRoleName = strRoleName1;
								
								tbName.text = _strRoleName;
								
								//发送请求用户列表消息
								SendReqRoleList();
							}
								break;
							case EnumType.NetMsg_RoleEvent_RoleIn:
							{
								_dictRoles[nRoleIndex1] = strRoleName1;
								
								ReflashRoleList();
							}
								break;
							case EnumType.NetMsg_RoleEvent_RoleOut:
							{
								delete _dictRoles[nRoleIndex1];
								
								ReflashRoleList();
							}
								break;
							default:
								break;
						}
						
					}
						break;
					case EnumType.NetMsg_ChatInfo:
					{
						switch (netMsg.GetIntValue("nChatType"))
						{
							case 1:
							case 2:
							{
								//var strMsg:String = netMsg.GetStringValue("szFromName") + " 对 " + netMsg.GetStringValue("szToName") + " 说: " + netMsg.GetStringValue("szContent");
								var strMsg:String = netMsg.GetStringValue("szFromName") + " 说: " + netMsg.GetStringValue("szContent");
								ShowText(strMsg);
							}
								break;
							default:
							break;
						}
					}
						break;
					case EnumType.NetMsg_RoleInfoList:
					{
						 if (netMsg.AbNetMsgHead.Number == _nReqRoleListMsgIndex)
						 {
							 var detailArr:Array = netMsg.GetArrayValue("info");
							 for (var i:int = 0; i < detailArr.length; i++)
							 {
								 var detail:NetMsgItem = detailArr[i] as NetMsgItem;
								 var nRoleIndex:int = detail.GetIntValue("nRoleIndex");
								 var strRoleName:String = detail.GetStringValue("szRoleName");
								 _dictRoles[nRoleIndex] = strRoleName;
							 }
							 
							 if (netMsg.AbNetMsgHead.EndFlag == EnumType.NetMsg_EndFlag_End)
							 {
								 //最后一个列表消息
								 //更新_arrayRole,并将_nReqRoleListMsgIndex置-1
								 ReflashRoleList();
							 }
						 }
					}
						break;
					default:
						break;
				}
			}
			
			//显示聊天内容
			public function ShowText(strText:String):void
			{
				if (strText == "")
					return;
				
				if (tbShow.text.length > 2000)
					tbShow.text = "";
				
				tbShow.text += strText + "\r\n";
				tbShow.scroller.verticalScrollBar.value = tbShow.scroller.verticalScrollBar.maximum;
			}
			
			protected function btCon_clickHandler(event:MouseEvent):void
			{
				// 开始连接到服务器
				_socketCon.m_socket.addEventListener(Event.CONNECT, OnConnect);
				
				var bState:Boolean = _socketCon.Connect(tbIP.text, int(tbPort.text));
			}
			
			//连接服务处理方法
			private function OnConnect(event:Event):void
			{
				var str:String = "已连接到: " + tbIP.text + ":" + tbPort.text;
				ShowText(str);
				
				SendRoleName();
				
				_socketCon.m_socket.removeEventListener(Event.CONNECT, OnConnect);
				
				_socketCon.m_socket.addEventListener(Event.CLOSE, OnDisConnect);
				
			}
			
			//断开服务连接处理方法
			private function OnDisConnect(event:Event):void
			{
				var str:String = "已断开连接: " + tbIP.text + ":" + tbPort.text;
				ShowText(str);
				
				_socketCon.m_socket.removeEventListener(Event.CLOSE, OnDisConnect);
			}
			
			//发送请求用户列表消息
			private function ReflashRoleList():void
			{
				_arrayRole.removeAll();
				_nReqRoleListMsgIndex = -1;
				for (var n:String in _dictRoles)
				{
					_arrayRole.addItem(_dictRoles[n]);
				}
			}
			
			private function SendReqRoleList():void
			{
				var msg:NetMsg = _socketCon.GetNetMsgProcessor.GetSendNetMsg(EnumType.NetMsg_RoleEvent);
				if (msg != null)
				{
					_nReqRoleListMsgIndex = msg.AbNetMsgHead.Number;
					
					msg.SetValue("nType", EnumType.NetMsg_RoleEvent_ReqRoleList);
					msg.SetValue("szRoleName", _strRoleName);
					msg.SetValue("nRoleIndex", _nRoleIndex);
					_socketCon.Send(msg);
				}
			}
			
			//发送登陆消息
			private function SendRoleName():void
			{
				var msg:NetMsg = _socketCon.GetNetMsgProcessor.GetSendNetMsg(EnumType.NetMsg_RoleEvent_Login);
				
				if (msg == null)
					return;
				
				msg.SetValue("nType", EnumType.NetMsg_RoleEvent_Login);
				msg.SetValue("szRoleName", _strRoleName);
				_socketCon.Send(msg);
			}

			protected function btSend_clickHandler(event:MouseEvent):void
			{
				// TODO Auto-generated method stub
				SendText();
			}
			
			//发送聊天消息
			private function SendText():void
			{
				var msg:NetMsg = _socketCon.GetNetMsgProcessor.GetSendNetMsg(EnumType.NetMsg_ChatInfo);
				
				if (msg == null)
					return;
				
				msg.SetValue("nChatType", EnumType.NetMsg_ChatInfo_Community);
				msg.SetValue("szFromName", _strRoleName);
				msg.SetValue("szToName", "大家");
				msg.SetValue("szContent", tbSend.text);
				_socketCon.Send(msg);
			}
		]]>
	</fx:Script>

	<fx:Declarations>
		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
	</fx:Declarations>
	<s:TextInput x="98" y="10" id="tbIP" width="86" text="127.0.0.1"/>
	<s:TextInput x="10" y="268" id="tbSend" width="290"/>
	<s:TextInput x="192" y="10" id="tbPort" width="41" text="4503"/>
	<s:TextInput x="320" y="10" id="tbName" width="70" text="FLEX"/>
	<s:Button x="10" y="10" label="连接到" id="btCon" click="btCon_clickHandler(event)"/>
	<s:TextArea x="10" y="39" id="tbShow" width="380" height="221"/>
	<s:Button x="320" y="269" label="发送" id="btSend" click="btSend_clickHandler(event)"/>
	<s:Label x="275" y="13" text="昵称:" fontSize="16"/>
	<s:Panel x="395" y="10" width="161" height="281" dropShadowVisible="false" borderVisible="true" title="参与聊天的人" fontWeight="normal">
		<s:List y="0" width="159" height="248" x="0" id="listRole"></s:List>
	</s:Panel>
</s:Application>

二、客户端消息

  客户端的消息结构定义在MSGConfig.xml文件中,同服务器端一样只有三种消息结构。

 “MSGConfig.xml”文件:定义消息结构

<?xml version="1.0" encoding="utf-8"?>
<Config>
  <Mapping type="1" name="RoleEvent">
    <Int name="nType"/>
    <String name="szRoleName" length="65" charset="utf-8"/>
    <Int name="nRoleIndex"/>
  </Mapping>

  <Mapping type="2" name="ChatInfo" comment = " 聊天">
    <Int name="nChatType"/>
    <String name="szFromName"  length="35" charset="utf-8" comment = " 聊天发送者名称"/>
    <String name="szToName" length="35" charset="utf-8" comment = " 聊天接收者名称"/>
    <String name="szContent" length="300" charset="utf-8" comment = " 聊天内容"/>
  </Mapping>

  <Mapping type="3" name="RoleInfoList" comment = " 用户列表">
    <Int name="nCount" comment = " 总数量"/>
    <Array name="info">
      <Item>
        <Int name="nRoleIndex" comment = "帐号索引"/>
        <String name="szRoleName" length="65" charset="utf-8" comment = " 发送人名称"/>
      </Item>
    </Array>
  </Mapping>
 </Config>

“MsgConfig.as”文件:将“MSGConfig.xml”中的消息格式读到内存中待用。

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	消息格式配置文件
 *********************************************************************/
package
{
	import flash.events.*;
	import flash.net.*;
	import flash.utils.Dictionary;
	
	import mx.collections.ArrayCollection;
	
	public class MsgConfig
	{
		private var _msgTypeMap:Dictionary = new Dictionary();
		private var _configXml:XML = null;
		public var m_bLoadFinish:Boolean = false;
		
		public function LoadConfig():void
		{
			
			if(m_bLoadFinish)
			{
				return;
			}
			
			var externalReq:URLRequest = new URLRequest("MSGConfig.xml");
			var externalLoad:URLLoader = new URLLoader();
			
			externalLoad.load(externalReq);
			externalLoad.addEventListener(Event.COMPLETE, TextReady);
		}
		
		
		private function TextReady(event:Event):void
		{
			_configXml = new XML(event.target.data);
			
			ReadMsgConfigXML();
			
			m_bLoadFinish = true;
		}
		
		private function ReadMsgConfigXML():void
		{
			var mapList:XMLList = _configXml.elements("Mapping");
			
			for each(var mapElement:XML in mapList)
			{
				var nType:int = mapElement.attribute("type");
				_msgTypeMap[nType] = mapElement;
			}
		}
		
		public function GetMappingByType(nType:int):XML
		{
			return _msgTypeMap[nType];
		}
	}
}

“NetMsgHead.as”文件:消息头文件

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	消息头
 *********************************************************************/
package
{
	public class NetMsgHead
	{
		private var m_size:int = 0;
		private var m_type:int = 0;
		private var m_endFlag:int = 0;
		private var m_number:int = 0;
		
		public function get Size():int
		{
			return m_size;
		}
		
		public function get Type():int
		{
			return m_type;
		}
		
		public function get EndFlag():int
		{
			return m_endFlag;
		}
		
		public function get Number():int
		{
			return m_number;
		}
		
		public function SetValue(nSize:int, nType:int, nEndFlag:int, nNumber:int):void
		{
			this.m_size = nSize;
			this.m_type = nType;
			this.m_endFlag = nEndFlag;
			this.m_number = nNumber;
		}
		
		public function NetMsgHead()
		{
		}
	}
}

“NetMsg.as”文件:消息类,根据字节流生成消息,根据消息生成字节流。这个类比银光客户端的“NetMsg”类更简洁一些。

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	消息类
 *********************************************************************/
package
{
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public class NetMsg
	{
		private var _paramMap:Object = new Object();
		private var _netMsgHead:NetMsgHead = new NetMsgHead();
		protected var _mappingElement:XML = null;
		
		//得消息头
		public function get AbNetMsgHead():NetMsgHead
		{
			return _netMsgHead;
		}
		
		public function NetMsg()
		{
		}
		
		//初始化一个不包含字节流的空消息供发送用
		public function InitNetMsg(xmlItem:XML, nType:int, nNumber:int):void
		{
			_mappingElement = xmlItem;
			
			this._netMsgHead.SetValue(0, nType, 0, nNumber);
		}
		
		//根据字节流生成消息(包含消息头的完整消息包)
		public function Parse(byteArray:ByteArray, xmlItem:XML):void
		{
			var nSize:int = byteArray.readInt();
			var nType:int = byteArray.readInt();
			var nEndFlag:int = byteArray.readInt();
			var nNumber:int = byteArray.readInt();
			
			this._netMsgHead.SetValue(nSize, nType, nEndFlag, nNumber);
			
			_mappingElement = xmlItem;
			
			this.PushData(byteArray);
		}
		
		//根据字节流生成消息(传入字节中已经去掉了消息头)
		protected function PushData(byteArray:ByteArray):void
		{
			var xmlList:XMLList = this._mappingElement.children();
			
			for each(var node:XML in xmlList)
			{
				var valueName:String = node.attribute("name");
				
				if(node.name() == "Int")
				{
					this.SetValue(valueName, byteArray.readInt());
				}
				else if(node.name() == "String")
				{
					var stringLength:int = new Number(node.attribute("length"));
					var charSet:String = node.attribute("charset");
					
					if(charSet == null)
					{
						charSet = "utf-8";
					}
					
					var value:String = byteArray.readMultiByte(stringLength, charSet);
					
					this.SetValue(valueName, value);
				}
				else if(node.name() == "Boolean")
				{
					this.SetValue(valueName, byteArray.readBoolean());
				}
				else if(node.name() == "Array")
				{
					byteArray.position = byteArray.position - 4;
					
					var count:int = byteArray.readInt();
					
					this.SetValue(valueName, this.GetArray(byteArray, count, node));
				}
				else if(node.name() == "Byte")
				{
					var b:int = byteArray.readByte();
					
					this.SetValue(valueName, b);
				}
				else if(node.name() == "Float")
				{
					var f:Number = byteArray.readFloat();
					
					this.SetValue(valueName, f);
				}
			}
		}
		
		//得字节流
		private function GetArray(byteArray:ByteArray, count:int, xml:XML):Array
		{
			var array:Array = new Array();
			
			var map:XML = xml.child("Item")[0];
			
			for(var i:int = 0 ; i < count ;i++)
			{
				var item:NetMsgItem = new NetMsgItem();
				
				item.ParseItem(byteArray, map);
				
				array.push(item);
			}
			
			return array;
		}
		
		public function SetValue(key:String, value:Object):void
		{
			this._paramMap[key] = value;
		}
		
		public function GetValue(key:String):Object
		{
			return this._paramMap[key];
		}
		
		public function GetIntValue(key:String):int
		{
			return this.GetValue(key) as int;
		}
		
		public function GetStringValue(key:String):String
		{
			return this.GetValue(key) as String;
		}
		
		public function GetArrayValue(key:String):Array
		{
			return this.GetValue(key) as Array;
		}
		
		public function GetBooleanValue(key:String):Boolean
		{
			return this.GetValue(key) as Boolean;
		}
		
		public function GetFloatValue(key:String):Number
		{
			return this.GetValue(key) as Number;
		}
		
		public function GetByte(key:String):int
		{
			var o:Object = this.GetValue(key);
			if(o is Number)
			{
				return o as int;
			}
			else
			{
				return o.toString().charCodeAt(0);
			}
		}
		
		//得此消息的字节流
		public function GetByteArray():ByteArray
		{
			var byteArray:ByteArray = new ByteArray();
			byteArray.endian = Endian.LITTLE_ENDIAN;
			
			//消息头
			byteArray.writeInt(0);		//length位置预留
			byteArray.writeInt(this._netMsgHead.Type);
			byteArray.writeInt(this._netMsgHead.EndFlag);
			byteArray.writeInt(this._netMsgHead.Number);
			
			//消息体
			this.GetBytes(byteArray);
			
			//重新定义消息长度
			byteArray.position = 0;
			byteArray.writeInt(byteArray.length);
			byteArray.position = 0;
			
			return byteArray;
		}
		
		//得消息体字节流
		protected function GetBytes(byteArray:ByteArray):void
		{
			var xmlList:XMLList= this._mappingElement.children();
			
			for each(var node:XML in xmlList)
			{
				var name:String = node.attribute("name");
				
				if(node.name() == "Int")
				{
					var value:Object = this.GetValue(name);
					
					if(value == null)
					{
						byteArray.writeInt(0);
					}
					else if(value is Number)
					{
						byteArray.writeInt(this.GetValue(name) as int);
					}
					else if(value is String)
					{
						byteArray.writeInt(new Number(this.GetValue(name)));
					}
				}
				else if(node.name() == "String")
				{
					var str:String = this.GetValue(name) as String;
					
					if(str == null)
					{
						str = "";
					}
					
					var length:int = new Number(node.attribute("length"));
					var charSet:String = node.attribute("charset");
					if(charSet == null)
					{
						charSet = "utf-8";
					}
					
					var tempArray:ByteArray = new ByteArray();
					tempArray.writeMultiByte(str, charSet);
					
					if(tempArray.length > length)
					{
						byteArray.writeBytes(tempArray,0,length);
					}
					else if(tempArray.length < length)
					{
						byteArray.writeBytes(tempArray);
						
						var lessLength:int = length - tempArray.length;
						
						while(--lessLength >= 0)
						{
							byteArray.writeByte(0);
						}
					}
					
				}
				else if(node.name() == "Boolean")
				{
					var b:Boolean = this.GetBooleanValue(name);
					
					byteArray.writeBoolean(b);
					
				}
				else if(node.name() == "Array")
				{
					var msgObjects:Array = this.GetArrayValue(name);
					
					if(msgObjects == null)
					{
						msgObjects = new Array();
					}
					else
					{
						var count:int = msgObjects.length;
						
						byteArray.writeInt(count);
						
						for(var i:int = 0 ; i < msgObjects.length ; i++)
						{
							var msgObject:NetMsgItem = msgObjects[i];
							byteArray.writeBytes(msgObject.GetItemByteArray(node.Item[0]));
						}
					}
				}
				else if(node.name() == "Byte")
				{
					byteArray.writeByte(this.GetByte(name));
				}
				else if(node.name() == "Float")
				{
					byteArray.writeFloat(this.GetFloatValue(name));
				}
			}
		}
	}

}

“NetMsgItem.as”文件:继承自NetMsg,为列表消息的列表项。

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	列表消息子项
 *********************************************************************/
package
{
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public class NetMsgItem extends NetMsg
	{
		public function NetMsgItem()
		{
		}
		
		//得列表项的字节流
		public function GetItemByteArray(xmlItem:XML):ByteArray
		{
			this._mappingElement = xmlItem;
			
			var byteArray:ByteArray = new ByteArray();
			byteArray.endian = Endian.LITTLE_ENDIAN;
			
			this.GetBytes(byteArray);
			
			return byteArray;
		}
		
		//根据字节流生成列表项
		public function ParseItem(byteArray:ByteArray, xmlItem:XML):void
		{
			this._mappingElement = xmlItem;
			
			this.PushData(byteArray);
		}
	}
}

“NetMsgProcessor.as”文件:加载消息格式,调用“字节流生成消息”方法,调用“取消息的字节流”方法

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	消息构建器
 *********************************************************************/
package
{
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public class NetMsgProcessor
	{
		private static var nNumber:int = 0;//同一批次消息的索引
		private var _xmlMsgConfig:MsgConfig = new MsgConfig();
		
		public function NetMsgProcessor()
		{
			Init();//目前在这里加载吧
		}
		
		public function Init():void
		{
			//加载配置文件
			_xmlMsgConfig.LoadConfig();
		}
		
		//从字节流生成消息
		public function BuildNetMsgFromBuffer(byteArray:ByteArray):NetMsg
		{
			byteArray.position = 4;
			var nMsgType:int = byteArray.readInt();
			
			var xmlItem:XML = _xmlMsgConfig.GetMappingByType(nMsgType);
			if (xmlItem == null)
				return null;
			
			byteArray.position = 0;
			
			var netMsg:NetMsg = new NetMsg();
			netMsg.Parse(byteArray, xmlItem);
			
			return netMsg;
		}
		
		//生成消息的字节流
		public function GetSendNetMsg(nMsgType:int):NetMsg
		{
			var xmlItem:XML = _xmlMsgConfig.GetMappingByType(nMsgType);
			if (xmlItem == null)
				return null;
			
			var netMsg:NetMsg = new NetMsg();
			netMsg.InitNetMsg(xmlItem, nMsgType, nNumber++);
			return netMsg;
		}
	}
}

“ReceiveEvent.as”文件:通知界面处理消息的事件

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	收到消息事件
 *********************************************************************/
package
{
	import flash.events.Event;
	
	public class ReceiveEvent extends Event
	{
		public static const Event_NetMsg:String = "NETMSG";
		
		public var m_netMsg:NetMsg = null;
		
		public function ReceiveEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
		}
		
		override public function clone():Event
		{
			var newEvent:ReceiveEvent = new ReceiveEvent(type);
			newEvent.m_netMsg = m_netMsg;
			return newEvent;
		}
	}
}

“EnumType.as”文件:消息类型。

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	消息类型,公共枚举
 *********************************************************************/
package
{
	public class EnumType
	{
		public static const NetMsg_RoleEvent:int = 1;
		public static const NetMsg_ChatInfo:int = 2;
		public static const NetMsg_RoleInfoList:int = 3;
		
		
		public static const NetMsg_ChatInfo_Community:int = 1;//公共聊天
		
		
		public static const NetMsg_RoleEvent_Login:int = 1;//用户登陆
		public static const NetMsg_RoleEvent_ValideLogin:int = 2;//验证用户登陆
		public static const NetMsg_RoleEvent_ReqRoleList:int = 3;//请求用户列表
		public static const NetMsg_RoleEvent_RoleIn:int = 4;//连接
		public static const NetMsg_RoleEvent_RoleOut:int = 5;//退出
		
		public static const NetMsg_EndFlag_Normal:int = 0;//普通消息
		public static const NetMsg_EndFlag_End:int = 1;//结束消息
		
		public function EnumType()
		{
		}
	}
}

三、客户端socket通讯连接

“SocketConnnector.as”文件:

/********************************************************************
 author:		田园小蛙 ourtree@live.cn
 
 purpose:	网络连接
 *********************************************************************/
package
{
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.Socket;
	import flash.system.Security;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public class SocketConnector extends EventDispatcher
	{
		public var m_socket:Socket = new Socket();
		
		private var _msgReceiveEvent:Object = new Object();
		
		private var _limitType:Object = new Object();
		
		private var _netMsgProcessor:NetMsgProcessor = null;
		
		private var m_bufRecvMsg:ByteArray = new ByteArray();//接收到不够组成一个包的数据缓冲
		
		public function get GetNetMsgProcessor():NetMsgProcessor
		{
			return _netMsgProcessor;
		}
		
		public function SocketConnector():void
		{
			
			m_socket.endian = Endian.LITTLE_ENDIAN;
			
			m_bufRecvMsg.endian = Endian.LITTLE_ENDIAN;
			
			_limitType[11] = true;
			
			Init();
		}
		
		public function Init():void
		{
			_netMsgProcessor = new NetMsgProcessor();
			
			BufReset();
		}
		
		public function Reset():void
		{
			m_socket = new Socket();
			
			BufReset();
		}
		
		//初始化数据缓存
		private function BufReset():void
		{
			m_bufRecvMsg.length = 1024 * 20;
			m_bufRecvMsg.clear();
		}
		
		/**
		 *m_socket 连接 
		 * */
		public function Connect(host:String,port:int):Boolean
		{
			flash.system.Security.loadPolicyFile("xmlm_socket://"+host+":"+port);
			
          	m_socket.addEventListener(Event.CLOSE, CloseHandler);
            
            //m_socket.addEventListener(ProgressEvent.SOCKET_DATA, InitHandler);
			m_socket.addEventListener(ProgressEvent.SOCKET_DATA, DataHandler);
			
            try
			{
				m_socket.connect(host,port);
            }
			catch (error:Error)
			{
                m_socket.close();
				
				return false;
            }
			
			return true;
		}
        
        private function CloseHandler(event:Event):void
		{
        }
        
		//收策略文件
        private function InitHandler(event:Event):void
		{
        	var tempByteArray:ByteArray  = new ByteArray();
        	tempByteArray.length = m_socket.bytesAvailable;
			
			if (tempByteArray.length > 0)
			{
				m_socket.readBytes(tempByteArray, 0, tempByteArray.length);
			}
        	
        	m_socket.removeEventListener(ProgressEvent.SOCKET_DATA, InitHandler);
        	m_socket.addEventListener(ProgressEvent.SOCKET_DATA, DataHandler);
        }
		
		//收字节流消息
		private function DataHandler(event:Event):void
		{
			var tempByteArray:ByteArray  = new ByteArray();
			tempByteArray.endian = Endian.LITTLE_ENDIAN;
			
			var nrevSize:int = m_socket.bytesAvailable;
			
			if (nrevSize > 0)
			{
				m_socket.readBytes(m_bufRecvMsg, m_bufRecvMsg.bytesAvailable, nrevSize);
				
				m_bufRecvMsg.position = 0;
				
				var nMsgLength:int = m_bufRecvMsg.readInt();
				var nMsgType:int = m_bufRecvMsg.readInt();
				
				m_bufRecvMsg.position = 0;
				
				while (m_bufRecvMsg.bytesAvailable >= nMsgLength)
				{
					
					var nLeftLength:int = m_bufRecvMsg.bytesAvailable - nMsgLength;//组成一包后多余的字节数
					
					//新建个消息包字节流
					var msgDataByteArray:ByteArray = new ByteArray();
					msgDataByteArray.endian = Endian.LITTLE_ENDIAN;
					msgDataByteArray.length = nMsgLength;
					msgDataByteArray.position = 0;
					
					//将字节拷入消息包流
					m_bufRecvMsg.readBytes(msgDataByteArray,0,nMsgLength);
					
					msgDataByteArray.bytesAvailable;
					
					//将剩余字节拷入接收缓存
					if (nLeftLength > 0)
					{
						m_bufRecvMsg.writeBytes(m_bufRecvMsg, 0, nLeftLength);
						
						nMsgLength = m_bufRecvMsg.readInt();
						nMsgType = m_bufRecvMsg.readInt();
						
						m_bufRecvMsg.position = 0;
					}
					else
					{
						BufReset();
					}
					
					//生成一个NetMsg包
					var netMsg:NetMsg = GetNetMsgProcessor.BuildNetMsgFromBuffer(msgDataByteArray);
					
					//分发包
					DispatchNetMsg(netMsg);
				}
			}
		}
		
        private function DispatchNetMsg(msg:NetMsg):void
		{
            var recvEvent:ReceiveEvent = new ReceiveEvent(ReceiveEvent.Event_NetMsg);
			recvEvent.m_netMsg = msg;
			dispatchEvent(recvEvent);
		}
        
        private function ErrorHandler(event:ErrorEvent):void
		{
        	trace("error");
        }
        
        private function IoErrorHandler(event:IOErrorEvent):void
		{
        	trace(event.text);
        }
		
        public function Send(msg:NetMsg):void
		{
        	if(!m_socket.connected)
			{
        		return;
        	}
        	
        	var byteArray:ByteArray = msg.GetByteArray();
        	
        	m_socket.writeBytes(byteArray);
        	
        	m_socket.flush();
        }
        
        public function get Connected():Boolean
		{
        	return m_socket.connected;
        }
        
        public function Close():void
		{
        	m_socket.close();
        }
	}
}

封装的socket连接类,接收和发送字节流消息,将收到消息将通知界面处理。

DataHandler(event:Event)方法处理收到的字节流,分析字节流是否够组成一个消息包,如果够就组成一个消息包并通知界面,不够就将收到的数据缓存(m_bufRecvMsg)起来。

以上就是整个FLEX客户端代码。(完)