Flex XmlSocket 跨域通信
闲来无事,温习了一下Socket编程,客户端基于FlexBuilder3.0,服务器基于VS2010C#开发。如下运行效果图:
登录界面:
登录后界面:
如果姓名有重复登录,系统会提示:
多个界面交互:
服务器截图:
客户端代码:
代码
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
backgroundGradientAlphas="[1.0, 0.81]" backgroundGradientColors="[#166065, #93F0F6]">
<mx:Style>
Application{
fontSize:12px;
}
</mx:Style>
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.formatters.DateFormatter;
import flash.events.Event;
import flash.events.DataEvent;
import mx.controls.Alert;
import flash.system.*;
private var socket:XMLSocket;
private var mydate:Date=new Date();
private var formatter:DateFormatter=new DateFormatter();
//连接服务器
private function ConnServer():void{
//formatter.formatString="YYYY-MM-DD JJ:NN:SS";
if(txtIP.text=="" || txtPort.text==''|| userName.text==''){
Alert.yesLabel="确定";
Alert.show("不能为空请填写!","提示",1);
return;
}
formatter.formatString="JJ:NN:SS";
currentState="loginState";
loginPanel.title="客户端-"+userName.text;
socket=new XMLSocket();
//添加事件侦听
socket.addEventListener(Event.CONNECT,OnConn);
socket.addEventListener(DataEvent.DATA,OnReceived);
socket.addEventListener(IOErrorEvent.IO_ERROR,isErrorHandler);
socket.connect(txtIP.text,int(txtPort.text));
textReceive.addEventListener(FlexEvent.VALUE_COMMIT,OnValueChange);
}
//设置接收信息区的滚动条
private function OnValueChange(evt:FlexEvent):void{
textReceive.verticalScrollPosition=textReceive.maxVerticalScrollPosition;
}
//连接完成执行函数
private function OnConn(evt:Event):void{
textReceive.htmlText="*******************<font color='#ff0000'>登录成功</font>********************\n";
//向服务器发送指令
socket.send("CONN|"+userName.text);
}
//接收服务器转播信息
private function OnReceived(evt:DataEvent):void{
if(evt.data=="Failed"){//接收失败重新登录连接服务器,客户端转向登录状态
currentState="";
loginPanel.title="客户端-未连接";
textReceive.text="";
Alert.yesLabel="确定";
Alert.show("姓名【"+userName.text+"】已被占用!","提示",1);
}else{//接收数据显示在客户端信息区
var arry:Array=evt.data.split('|',evt.data.length);
textReceive.text+="【"+arry[0]+" 在"+formatter.format(mydate)+"】说:\n"+arry[1]+"\n";
}
}
//连接服务器报错处理
private function isErrorHandler(evt:IOErrorEvent):void{
currentState="";
loginPanel.title="客户端-未连接";
Alert.yesLabel="确定";
Alert.show(evt.text,"提示",1,this);
}
//客户端向服务器发送消息
private function sendMsg():void{
if(txtIP.text=="" || txtPort.text==""){
currentState="";
loginPanel.title="客户端-未连接";
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
backgroundGradientAlphas="[1.0, 0.81]" backgroundGradientColors="[#166065, #93F0F6]">
<mx:Style>
Application{
fontSize:12px;
}
</mx:Style>
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.formatters.DateFormatter;
import flash.events.Event;
import flash.events.DataEvent;
import mx.controls.Alert;
import flash.system.*;
private var socket:XMLSocket;
private var mydate:Date=new Date();
private var formatter:DateFormatter=new DateFormatter();
//连接服务器
private function ConnServer():void{
//formatter.formatString="YYYY-MM-DD JJ:NN:SS";
if(txtIP.text=="" || txtPort.text==''|| userName.text==''){
Alert.yesLabel="确定";
Alert.show("不能为空请填写!","提示",1);
return;
}
formatter.formatString="JJ:NN:SS";
currentState="loginState";
loginPanel.title="客户端-"+userName.text;
socket=new XMLSocket();
//添加事件侦听
socket.addEventListener(Event.CONNECT,OnConn);
socket.addEventListener(DataEvent.DATA,OnReceived);
socket.addEventListener(IOErrorEvent.IO_ERROR,isErrorHandler);
socket.connect(txtIP.text,int(txtPort.text));
textReceive.addEventListener(FlexEvent.VALUE_COMMIT,OnValueChange);
}
//设置接收信息区的滚动条
private function OnValueChange(evt:FlexEvent):void{
textReceive.verticalScrollPosition=textReceive.maxVerticalScrollPosition;
}
//连接完成执行函数
private function OnConn(evt:Event):void{
textReceive.htmlText="*******************<font color='#ff0000'>登录成功</font>********************\n";
//向服务器发送指令
socket.send("CONN|"+userName.text);
}
//接收服务器转播信息
private function OnReceived(evt:DataEvent):void{
if(evt.data=="Failed"){//接收失败重新登录连接服务器,客户端转向登录状态
currentState="";
loginPanel.title="客户端-未连接";
textReceive.text="";
Alert.yesLabel="确定";
Alert.show("姓名【"+userName.text+"】已被占用!","提示",1);
}else{//接收数据显示在客户端信息区
var arry:Array=evt.data.split('|',evt.data.length);
textReceive.text+="【"+arry[0]+" 在"+formatter.format(mydate)+"】说:\n"+arry[1]+"\n";
}
}
//连接服务器报错处理
private function isErrorHandler(evt:IOErrorEvent):void{
currentState="";
loginPanel.title="客户端-未连接";
Alert.yesLabel="确定";
Alert.show(evt.text,"提示",1,this);
}
//客户端向服务器发送消息
private function sendMsg():void{
if(txtIP.text=="" || txtPort.text==""){
currentState="";
loginPanel.title="客户端-未连接";
return;
}
if(socket.connected){
if(textSend.text==""){
Alert.yesLabel="确定";
Alert.show("发送内容不能为空!","提示",1);
return;
}
socket.send(userName.text+"|"+textSend.text);
textReceive.text+="【"+userName.text+" 在"+formatter.format(mydate)+"】说:\n"+textSend.text+"\n";
textSend.text="";
}
else{
currentState="";
loginPanel.title="客户端-未连接";
Alert.yesLabel="确定";
Alert.show("登录服务器失败,请从新登录!","提示",1);
}
}
]]>
</mx:Script>
<!--登录成功后把Panel的状态设为loginState-->
<mx:states>
<mx:State name="loginState">
<mx:RemoveChild target="{label1}"/>
<mx:RemoveChild target="{txtIP}"/>
<mx:RemoveChild target="{txtPort}"/>
<mx:RemoveChild target="{label2}"/>
<mx:RemoveChild target="{btnCon}"/>
<mx:SetProperty target="{textReceive}" name="height" value="212"/>
<mx:SetProperty target="{textReceive}" name="y" value="10"/>
<mx:RemoveChild target="{label3}"/>
<mx:RemoveChild target="{userName}"/>
</mx:State>
</mx:states>
<!--登录成功后播放2秒钟动画把Panel状态改为loginState-->
<mx:transitions>
<mx:Transition>
<mx:Iris duration="2000" targets="{[loginPanel]}">
</mx:Iris>
</mx:Transition>
</mx:transitions>
<!--客户端窗口设计-->
<mx:Panel id="loginPanel" width="423" height="358" layout="absolute" horizontalCenter="0" y="131" title="客户端" backgroundAlpha="0.8">
<mx:TextArea id="textReceive" x="10" y="45" width="383" height="177"/>
<mx:TextArea id="textSend" x="10" y="230" width="323" height="76"/>
<mx:Button id="btnSend" click="sendMsg()" y="229" label="发送" height="77" x="341" fillAlphas="[1.0, 1.0, 0.9, 0.9]" fillColors="[#25B9BE, #DAE9EA, #148A8E, #3CEEF4]"/>
<mx:Label x="10" y="10" text="IP:" fontWeight="bold" id="label1"/>
<mx:TextInput id="txtIP" x="35" y="8" width="97" text="192.168.1.35"/>
<mx:Label x="134" y="10" text="Port:" fontWeight="bold" id="label2"/>
<mx:TextInput id="txtPort" x="170" y="8" width="44" text="1234"/>
<mx:Button id="btnCon" click="ConnServer()" x="341" y="9" label="登录" fillAlphas="[1.0, 1.0]" fillColors="[#F8A5BB, #F20C5D]" width="52"/>
<mx:Label x="214" y="11" text="姓名:" fontWeight="bold" id="label3"/>
<mx:TextInput id="userName" x="255" y="8" width="80" text="风行者"/>
</mx:Panel>
</mx:Application>
}
if(socket.connected){
if(textSend.text==""){
Alert.yesLabel="确定";
Alert.show("发送内容不能为空!","提示",1);
return;
}
socket.send(userName.text+"|"+textSend.text);
textReceive.text+="【"+userName.text+" 在"+formatter.format(mydate)+"】说:\n"+textSend.text+"\n";
textSend.text="";
}
else{
currentState="";
loginPanel.title="客户端-未连接";
Alert.yesLabel="确定";
Alert.show("登录服务器失败,请从新登录!","提示",1);
}
}
]]>
</mx:Script>
<!--登录成功后把Panel的状态设为loginState-->
<mx:states>
<mx:State name="loginState">
<mx:RemoveChild target="{label1}"/>
<mx:RemoveChild target="{txtIP}"/>
<mx:RemoveChild target="{txtPort}"/>
<mx:RemoveChild target="{label2}"/>
<mx:RemoveChild target="{btnCon}"/>
<mx:SetProperty target="{textReceive}" name="height" value="212"/>
<mx:SetProperty target="{textReceive}" name="y" value="10"/>
<mx:RemoveChild target="{label3}"/>
<mx:RemoveChild target="{userName}"/>
</mx:State>
</mx:states>
<!--登录成功后播放2秒钟动画把Panel状态改为loginState-->
<mx:transitions>
<mx:Transition>
<mx:Iris duration="2000" targets="{[loginPanel]}">
</mx:Iris>
</mx:Transition>
</mx:transitions>
<!--客户端窗口设计-->
<mx:Panel id="loginPanel" width="423" height="358" layout="absolute" horizontalCenter="0" y="131" title="客户端" backgroundAlpha="0.8">
<mx:TextArea id="textReceive" x="10" y="45" width="383" height="177"/>
<mx:TextArea id="textSend" x="10" y="230" width="323" height="76"/>
<mx:Button id="btnSend" click="sendMsg()" y="229" label="发送" height="77" x="341" fillAlphas="[1.0, 1.0, 0.9, 0.9]" fillColors="[#25B9BE, #DAE9EA, #148A8E, #3CEEF4]"/>
<mx:Label x="10" y="10" text="IP:" fontWeight="bold" id="label1"/>
<mx:TextInput id="txtIP" x="35" y="8" width="97" text="192.168.1.35"/>
<mx:Label x="134" y="10" text="Port:" fontWeight="bold" id="label2"/>
<mx:TextInput id="txtPort" x="170" y="8" width="44" text="1234"/>
<mx:Button id="btnCon" click="ConnServer()" x="341" y="9" label="登录" fillAlphas="[1.0, 1.0]" fillColors="[#F8A5BB, #F20C5D]" width="52"/>
<mx:Label x="214" y="11" text="姓名:" fontWeight="bold" id="label3"/>
<mx:TextInput id="userName" x="255" y="8" width="80" text="风行者"/>
</mx:Panel>
</mx:Application>
跨域访问安全沙箱设置:
如果不设置,是不能通信的并且包如下错误:
登录客户端时,客户端会向服务器发送字符串:<policy-file-request/>,在服务器端只需检测该字符串,收到后回发一条如下信息:即可解决安全沙箱冲突问题。
string onemessage = "<cross-domain-policy><allow-access-from domain=\"" + "*" + "\" to-ports=\"1234\"/></cross-domain-policy>\0";
byte[] buffer = Encoding.UTF8.GetBytes(onemessage);
socket.Send(buffer);
服务器端代码:请参考以前发表的【C#局域网通信】(C#.net分类里)
http://www.cnblogs.com/Xingsoft-555/archive/2009/12/13/1622829.html