• Flex通信-与Java实现Socket通信实例


    Flex通信-与Java实现Socket通信实例  转自:http://blessht.iteye.com/blog/1136888

    博客分类:

    • 环境准备
    【服务器端】
    JDK1.6,“java.net”包对网络编程提供了非常全面的支持,包括Socket
    开发环境:Eclipse
    【客户端】
    Flex4,”flash.net”包也提供了Socket的支持
    开发环境:FlashBuilder4
     
    • 实例效果
    我是用Java启动一个ServerSocket作为服务器,Flex创建一个页面,当点击页面上的按钮时向Java服务器发送消息。
     
    Flex客户端输入“阿里巴巴”再点击按钮:

     Java控制台:


     
     
    • 注意事项
    Flex项目分为两种:一种是普通的本地项目,也就是不依赖其它服务器;另一种是远程服务器项目,这需要依赖其它语言的服务器容器。如果是普通的本地项目,Socket通信是非常容易的,但是如果是远程项目,Socket通信需要考虑Flex安全沙箱问题,后面会详细介绍。


     
     
    • Java Socket服务器
    编写Socket Server代码的步骤通常是:
    ①创建ServerSocket,定义服务端口号
    ②使用ServerSocket.accept()监听socket请求,如果有请求会创建一个Socket对象
    ③通过socket.getInputStream()获取客户端的请求数据
    ④通过socket.getOutputStream()向客户端返回数据
    ⑤通过socket.close()结束本次会话
    按照上面的步骤,如果有多个客户端向服务器发送请求的话,服务器只会处理第一个请求,其它请求会排队等待,只有第一个请求执行socket.close的时候下一个客户端请求才会运行。为了实现多客户端并发请求,在第②步后面需要建立多线程。
     
    废话不多说,直接代码说明。
     
    首先创建一个SocketUtil类,用于创建ServerSocket和获取Socket
    Java代码  
    1. public class SocketUtil {   
    2.        
    3.     /**  
    4.      * 创建ServerSocket  
    5.      * @param port  
    6.      * @return  
    7.      */  
    8.     public static ServerSocket getServerSocket(int port){   
    9.         ServerSocket server = null;   
    10.         try {   
    11.             server = new ServerSocket(port);   
    12.             System.out.println("------ServerSocket创建成功,Port:"+port);   
    13.             return server;   
    14.         } catch (IOException e) {   
    15.             if(server!=null && !server.isClosed()){   
    16.                 try {   
    17.                     server.close();   
    18.                 } catch (IOException e1) {   
    19.                     e1.printStackTrace();   
    20.                 }   
    21.             }   
    22.             throw new RuntimeException("创建ServerSocket时发生异常,Port:"+port,e);   
    23.         }   
    24.     }   
    25.        
    26.     /**  
    27.      * 获取Socket  
    28.      * @param server  
    29.      * @return  
    30.      */  
    31.     public static Socket getSocket(ServerSocket server){   
    32.         Socket socket = null;   
    33.         try {   
    34.             socket = server.accept();   
    35.             System.out.println("------Socket连接成功,IP:"+socket.getInetAddress());   
    36.             return socket;   
    37.         } catch (IOException e) {   
    38.             if(socket!=null && !socket.isClosed()){   
    39.                 try {   
    40.                     socket.close();   
    41.                 } catch (IOException e1) {   
    42.                     e1.printStackTrace();   
    43.                 }   
    44.             }   
    45.             throw new RuntimeException("创建Socket时发送异常",e);   
    46.         }   
    47.     }   
    48.        
    49. }  
     
    然后创建一个带多线程的类,用于服务器与客户端的IO通信
    Java代码  
    1. public class SocketThread implements Runnable {   
    2.     private Socket socket;   
    3.     private String encoding;   
    4.        
    5.     public SocketThread(Socket socket,String encoding) {   
    6.         this.socket = socket;   
    7.         this.encoding = encoding;   
    8.     }   
    9.        
    10.     /**  
    11.      * 与客户端交互代码  
    12.      */  
    13.     @Override  
    14.     public void run() {   
    15.         try {   
    16.             BufferedReader br = new BufferedReader(new InputStreamReader(socket   
    17.                     .getInputStream(), encoding));   
    18.             BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(   
    19.                     socket.getOutputStream(), encoding));   
    20.                
    21.             String getMsg;   
    22.             while ((getMsg = br.readLine()) != null && !"exit".equalsIgnoreCase(getMsg)) {   
    23.                 // 客户端未提出"exit"命令,则循环交流   
    24.                 System.out.println("From client message:" + getMsg);   
    25.                 bw.append("你好[" + socket.getInetAddress() + "],服务器收到你的信息:"  
    26.                         + getMsg + " ");   
    27.                 bw.flush();   
    28.             }   
    29.                
    30.             //客户端提出"exit"请求,关闭当前socket...   
    31.             br.close();   
    32.             bw.close();   
    33.             socket.close();   
    34.             System.out.println("当前Socket连接结束......");   
    35.         } catch (Exception e) {   
    36.             if(!socket.isClosed()){   
    37.                 try {   
    38.                     socket.close();   
    39.                 } catch (IOException e1) {   
    40.                     e1.printStackTrace();   
    41.                 }   
    42.             }   
    43.             throw new RuntimeException("Socket线程类发送异常...",e);   
    44.         }   
    45.     }   
    46. }  
     
    最后在Main函数中启动Socket服务即可:
    Java代码  
    1. public static void main(String[] args) {   
    2.         new SocketServer().startSocket();   
    3.     }  
     
    • Flex客户端代码
    Flex端创建Socket有两种方式:
    第一种通过connect方法连接Socket服务器:
    Java代码 复制代码 收藏代码
    1. var socket:Socket = new Socket();   
    2. socket.connect("localhost",10086);  
     第二种通过创建Socket实例时在构造函数中传入服务器ip和端口号连接:
    Java代码  
    1. socket = new Socket("localhost",10086);  
     Flex通过ByteArray传送IO数据,这里有一点稍微注意一下在写入的内容后面会加" "回车换行符,因为java端是通过BufferedReader.readLine的形式获取一行数据,如果不换行服务器端IO就一直处于阻塞状态:
    Java代码  
    1. //ByteArray存放数据   
    2. var message:ByteArray = new ByteArray();   
    3. //使用UTF形式防止中文乱码   
    4. message.writeUTFBytes(txt_socket.text+" ");   
    5. //数据写入缓冲区   
    6. socket.writeBytes(message);  
     Flex有多种事件用于监听Socket的状态:
    Java代码  
    1. Event.CONNECT:Socket与服务器成功连接时触发的事件   
    2. Event.CLOSE:Socket与服务器断开连接时触发的事件   
    3. IOErrorEvent.IO_ERROR:Socket通信时发生IO错误时触发的事件   
    4. ProgressEvent.SOCKET_DATA:服务器返回数据时触发的事件  
     
    新建一个Flex普通项目,入口文件定义为index.mxml,在mxml文件中新建一个textinput文本框用于获取用户输入的内容,button按钮用户发送内容到java socket服务器,一个label用户显示向前socket状态,另一个label用于显示从服务器返回的信息。 index.mxml代码如下:
    Xml代码  
    1. <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"    
    2.                xmlns:s="library://ns.adobe.com/flex/spark"    
    3.                xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">  
    4.   
    5.     <fx:Script>  
    6.         <![CDATA[  
    7.               
    8.               
    9.             private var socket:Socket = null;  
    10.             protected function button1_clickHandler(event:MouseEvent):void  
    11.             {  
    12.                 if(socket==null || !socket.connected){  
    13.                     //连接服务器(ip,port)  
    14.                     socket = new Socket("localhost",10086);  
    15.                       
    16.                     //成功连接状态事件  
    17.                     socket.addEventListener(Event.CONNECT,function connFun(e:Event):void{  
    18.                         l_status.text = "Connect to server success...";  
    19.                     });  
    20.                     //连接中断事件  
    21.                     socket.addEventListener(Event.CLOSE,function closeFun(e:Event):void{  
    22.                         l_status.text = "Connect to server closed...";  
    23.                     });  
    24.                     //连接异常事件  
    25.                     socket.addEventListener(IOErrorEvent.IO_ERROR,function closeFun(e:IOErrorEvent):void{  
    26.                         l_status.text = "Connect exception ..."+e.toString();  
    27.                     });  
    28.                     //服务器信息事件  
    29.                     socket.addEventListener(ProgressEvent.SOCKET_DATA,function dataFun(e:ProgressEvent):void{  
    30.                         var getMsg:ByteArray = new ByteArray;  
    31.                         socket.readBytes(getMsg);  
    32.                         l_result.text = getMsg.toString();  
    33.                     });  
    34.                 }  
    35.                   
    36.                 //ByteArray存放数据  
    37.                 var message:ByteArray = new ByteArray();  
    38.                 //使用UTF形式防止中文乱码  
    39.                 message.writeUTFBytes(txt_socket.text+" ");  
    40.                 //数据写入缓冲区  
    41.                 socket.writeBytes(message);  
    42.                 //将缓冲区数据发送出去  
    43.                 socket.flush();  
    44.                 //清空文本框内容  
    45.                 txt_socket.text = "";  
    46.             }  
    47.         ]]>  
    48.     </fx:Script>  
    49.   
    50.     <fx:Declarations>  
    51.         <!-- 将非可视元素(例如服务、值对象)放在此处 -->  
    52.     </fx:Declarations>  
    53.     <s:Button x="156" y="56" label="按钮" click="button1_clickHandler(event)"/>  
    54.     <s:TextInput x="20" y="56" id="txt_socket"/>  
    55.     <s:Label x="20" y="104" id="l_status"/>  
    56.     <s:Label x="234" y="65" id="l_result"/>  
    57. </s:Application>  
     
    代码编写完成后运行index.mxml文件,最后执行效果就如前面【实例效果】所示。
     
     
    • 安全沙箱
    下面这段是从网上抄的:
    ----------------------------------------------------------------------------
    在 Adobe Flash Player 升级到 9.0.124 后,由于安全策略更改,原来 Socket 或 XmlSocket 的应用里的 http 方式加载安全策略的手段不能继续使用。更改如下:
    1, 首先检测目标服务器的 843 端口是否提供安全策略 

    2, 如果 1 没有检测到策略,则检测 actionscript 是否使用了 Security.loadPolicyFile(xmlsocket://)手段提供安全策略,如果还没检测到,则使用第 3 步检测
    3, 检测目标服务器目标端口是否提供安全策略。

    在说具体处理方式前,我先描述一下 Flash Player 的验证过程。在 Flex 程序发出 Socket 或 XmlSocket( 以下统称为 Socket) 请求前, FlashPlayer 会先判断是否为本地调用,如果不是。即用一个 Socket 去链接到你的服务端,三次握手成功后一方面发出字符串“ <policy-file-request/> “另一方面监听返回的安全策略。安全策略接收成功后, FlashPlayer 就断开验证的 Socket ,然后再运行程序本身的 Socket 。在整个 SWF 运行期间,无论你请求多少次,只要域相同, FlashPlayer 就只验证一次。这里有两个重点:
     
    第一个是验证的 Socket 和程序的 Socket 是两个 Socket 。所以你在本地测试时,服务端监听到 N 个 Socket 请求,但布置到服务端后,服务端会监听到 N+1 个请求。
    第二是验证的 Socket 发送“ <policy-file-request/> “请求和接收你的策略文件是没有先后关系的,所以你没必要接收完“ <policy-file-request/> “后才发策略文件。我的做法是只要监听到请求,就把策略字符串发过去。
    -----------------------------------------------------------------------------------
     
    那么简单的说,如果Flex项目依赖其它语言的服务器的话(比如依赖J2EE服务器),在flex的socket客户端向JavaSocket服务器发送请求之前,Flex会优先发送一个安全验证消息,如果java服务器不返回验证消息则当前socket通信失败。
    解决办法有很多种,我在网上也看了很多,但是很多写得有问题。
    根据我多方调查,个人觉得这种方案比较靠谱:
    在Java服务器端创建一个端口号为843的ServerSocket监听Flex安全沙箱验证消息,如果接收到<policy-file-request/>文件信息,则向客户端返回XMl验证内容:“<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>”
    具体代码如下:
    Java代码  
    1. /**  
    2.  * 处理与Flex认证的线程类  
    3.  * @author Administrator  
    4.  */  
    5. public class PolicyThread implements Runnable {   
    6.     private final String policy_xml = "<policy-file-request/>";   
    7.     private final String cross_xml = "<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>";   
    8.     private Socket socket;   
    9.        
    10.     public PolicyThread(Socket socket){   
    11.         this.socket = socket;   
    12.     }   
    13.        
    14.     @Override  
    15.     public void run() {   
    16.         try {   
    17.             //接收并发送Flex安全验证请求   
    18.             BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));   
    19.             PrintWriter pw = new PrintWriter(socket.getOutputStream());   
    20.             char[] by = new char[22];   
    21.             br.read(by, 022);   
    22.             String s = new String(by);   
    23.             if(s.equals(policy_xml)){   
    24.                 System.out.println("接收policy-file-request认证");   
    25.                 pw.print(cross_xml);   
    26.                 pw.flush();   
    27.                 br.close();   
    28.                 pw.close();   
    29.                 socket.close();   
    30.                 System.out.println("完成policy-file-request认证");   
    31.             }   
    32.         } catch (IOException e) {   
    33.             if(!socket.isClosed()){   
    34.                 try {   
    35.                     socket.close();   
    36.                 } catch (IOException e1) {   
    37.                     e1.printStackTrace();   
    38.                 }   
    39.             }   
    40.             throw new RuntimeException("执行policy认证时发生异常",e);   
    41.         }   
    42.     }   
    43.   
    44. }  
    Java代码  
    1. public class PolicyServer implements Runnable{   
    2.        
    3.     private final int policy_port = 843;   
    4.     private boolean status = true;   
    5.        
    6.     private ServerSocket server = null;   
    7.     @Override  
    8.     public void run() {   
    9.         //创建安全验证服务器   
    10.         server = SocketUtil.getServerSocket(policy_port);   
    11.            
    12.         while(status){   
    13.             Socket socket = SocketUtil.getSocket(server);   
    14.             new Thread(new PolicyThread(socket)).start();   
    15.         }   
    16.     }   
    17.        
    18.        
    19.     /**  
    20.      * 启动服务器  
    21.      */  
    22.     public void startPolicy(){   
    23.         new Thread(this).start();   
    24.     }   
    25.        
    26.     /**  
    27.      * 关闭服务器  
    28.      */  
    29.     public void stopPolicy(){   
    30.         status = false;   
    31.         if(server!=null && !server.isClosed()){   
    32.             try {   
    33.                 server.close();   
    34.             } catch (IOException e) {   
    35.                 e.printStackTrace();   
    36.             }   
    37.         }   
    38.     }   
    39. }  
     
    Flex客户端向Java发送第一次Socket请求(例子里的端口号是10086)时,ServerSocket843端口会收到安全沙箱验证,随后server将正确的验证消息返回给Flex客户端,Flex认证成功后真正的10086端口Socket连结就已经搭建了,随后双方就可以畅通无阻通信了(一次会话只进行一次沙箱验证)。
     
     
    • Servlet启动ServerSocket
    我通常比较喜欢创建一个servlet,在web.xml中配置容器启动时运行servlet的init方法,这样端口号为10086和843的serverSocket就会启动:
    Java代码  
    1. public class InitServers extends HttpServlet {   
    2.     private static final long serialVersionUID = 1L;   
    3.           
    4.     /**  
    5.      * @see HttpServlet#HttpServlet()  
    6.      */  
    7.     public InitServers() {   
    8.         super();   
    9.     }   
    10.   
    11.     /**  
    12.      * @see Servlet#init(ServletConfig)  
    13.      */  
    14.     public void init(ServletConfig config) throws ServletException {   
    15.         new PolicyServer().startPolicy();   
    16.         new SocketServer().startSocket();   
    17.     }   
    18.   
    19.     /**  
    20.      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)  
    21.      */  
    22.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {   
    23.         // TODO Auto-generated method stub   
    24.     }   
    25.   
    26.     /**  
    27.      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)  
    28.      */  
    29.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {   
    30.         // TODO Auto-generated method stub   
    31.     }   
    32.   
    33. }  
     web.xml
     
    Xml代码  
    1. <servlet>  
    2.         <display-name>InitServers</display-name>  
    3.         <servlet-name>InitServers</servlet-name>  
    4.         <servlet-class>socket.InitServers</servlet-class>  
    5.         <load-on-startup>1</load-on-startup>  
    6.     </servlet>  
     
    以上一个完整的Flex+Java的Socket通信就完成了。
  • 相关阅读:
    罗马数字转换成整数
    整数转换成罗马数字
    hdu 5050 大数
    hdu 5051 找规律?+大trick
    hdu 5055
    hdu 5054
    hdu 5058 set应用
    hdu 5056 所有字母数都<=k的子串数目
    hdu 5059 简单字符串处理
    hdu 5060 五种情况求圆柱体与球体交
  • 原文地址:https://www.cnblogs.com/lbangel/p/3181356.html
Copyright © 2020-2023  润新知