瘋狂

          STANDING ON THE SHOULDERS OF GIANTS
          posts - 481, comments - 486, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          Flex通信-與Java實(shí)現(xiàn)Socket通信實(shí)例

          Posted on 2011-10-09 17:28 瘋狂 閱讀(3894) 評論(0)  編輯  收藏 所屬分類: flex

          Flex通信-與Java實(shí)現(xiàn)Socket通信實(shí)例  轉(zhuǎn)自:http://blessht.iteye.com/blog/1136888

          • 環(huán)境準(zhǔn)備
          【服務(wù)器端】
          JDK1.6,“java.net”包對網(wǎng)絡(luò)編程提供了非常全面的支持,包括Socket
          開發(fā)環(huán)境:Eclipse
          【客戶端】
          Flex4,”flash.net”包也提供了Socket的支持
          開發(fā)環(huán)境:FlashBuilder4

          • 實(shí)例效果
          我是用Java啟動一個(gè)ServerSocket作為服務(wù)器,F(xiàn)lex創(chuàng)建一個(gè)頁面,當(dāng)點(diǎn)擊頁面上的按鈕時(shí)向Java服務(wù)器發(fā)送消息。

          Flex客戶端輸入“阿里巴巴”再點(diǎn)擊按鈕:

           Java控制臺:


           

          • 注意事項(xiàng)
          Flex項(xiàng)目分為兩種:一種是普通的本地項(xiàng)目,也就是不依賴其它服務(wù)器;另一種是遠(yuǎn)程服務(wù)器項(xiàng)目,這需要依賴其它語言的服務(wù)器容器。如果是普通的本地項(xiàng)目,Socket通信是非常容易的,但是如果是遠(yuǎn)程項(xiàng)目,Socket通信需要考慮Flex安全沙箱問題,后面會詳細(xì)介紹。


           

          • Java Socket服務(wù)器
          編寫Socket Server代碼的步驟通常是:
          ①創(chuàng)建ServerSocket,定義服務(wù)端口號
          ②使用ServerSocket.accept()監(jiān)聽socket請求,如果有請求會創(chuàng)建一個(gè)Socket對象
          ③通過socket.getInputStream()獲取客戶端的請求數(shù)據(jù)
          ④通過socket.getOutputStream()向客戶端返回?cái)?shù)據(jù)
          ⑤通過socket.close()結(jié)束本次會話
          按照上面的步驟,如果有多個(gè)客戶端向服務(wù)器發(fā)送請求的話,服務(wù)器只會處理第一個(gè)請求,其它請求會排隊(duì)等待,只有第一個(gè)請求執(zhí)行socket.close的時(shí)候下一個(gè)客戶端請求才會運(yùn)行。為了實(shí)現(xiàn)多客戶端并發(fā)請求,在第②步后面需要建立多線程。

          廢話不多說,直接代碼說明。

          首先創(chuàng)建一個(gè)SocketUtil類,用于創(chuàng)建ServerSocket和獲取Socket
          Java代碼  
          1. public class SocketUtil {   
          2.        
          3.     /**  
          4.      * 創(chuàng)建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創(chuàng)建成功,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("創(chuàng)建ServerSocket時(shí)發(fā)生異常,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("創(chuàng)建Socket時(shí)發(fā)送異常",e);   
          46.         }   
          47.     }   
          48.        
          49. }  
           
          然后創(chuàng)建一個(gè)帶多線程的類,用于服務(wù)器與客戶端的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"命令,則循環(huán)交流   
          24.                 System.out.println("From client message:" + getMsg);   
          25.                 bw.append("你好[" + socket.getInetAddress() + "],服務(wù)器收到你的信息:"  
          26.                         + getMsg + "\r\n");   
          27.                 bw.flush();   
          28.             }   
          29.                
          30.             //客戶端提出"exit"請求,關(guān)閉當(dāng)前socket...   
          31.             br.close();   
          32.             bw.close();   
          33.             socket.close();   
          34.             System.out.println("當(dāng)前Socket連接結(jié)束......");   
          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線程類發(fā)送異常...",e);   
          44.         }   
          45.     }   
          46. }  
           
          最后在Main函數(shù)中啟動Socket服務(wù)即可:
          Java代碼  
          1. public static void main(String[] args) {   
          2.         new SocketServer().startSocket();   
          3.     }  
           
          • Flex客戶端代碼
          Flex端創(chuàng)建Socket有兩種方式:
          第一種通過connect方法連接Socket服務(wù)器:
          Java代碼 復(fù)制代碼 收藏代碼
          1. var socket:Socket = new Socket();   
          2. socket.connect("localhost",10086);  
           第二種通過創(chuàng)建Socket實(shí)例時(shí)在構(gòu)造函數(shù)中傳入服務(wù)器ip和端口號連接:
          Java代碼  
          1. socket = new Socket("localhost",10086);  
           Flex通過ByteArray傳送IO數(shù)據(jù),這里有一點(diǎn)稍微注意一下在寫入的內(nèi)容后面會加"\r\n"回車換行符,因?yàn)閖ava端是通過BufferedReader.readLine的形式獲取一行數(shù)據(jù),如果不換行服務(wù)器端IO就一直處于阻塞狀態(tài):
          Java代碼  
          1. //ByteArray存放數(shù)據(jù)   
          2. var message:ByteArray = new ByteArray();   
          3. //使用UTF形式防止中文亂碼   
          4. message.writeUTFBytes(txt_socket.text+"\r\n");   
          5. //數(shù)據(jù)寫入緩沖區(qū)   
          6. socket.writeBytes(message);  
           Flex有多種事件用于監(jiān)聽Socket的狀態(tài):
          Java代碼  
          1. Event.CONNECT:Socket與服務(wù)器成功連接時(shí)觸發(fā)的事件   
          2. Event.CLOSE:Socket與服務(wù)器斷開連接時(shí)觸發(fā)的事件   
          3. IOErrorEvent.IO_ERROR:Socket通信時(shí)發(fā)生IO錯(cuò)誤時(shí)觸發(fā)的事件   
          4. ProgressEvent.SOCKET_DATA:服務(wù)器返回?cái)?shù)據(jù)時(shí)觸發(fā)的事件  

          新建一個(gè)Flex普通項(xiàng)目,入口文件定義為index.mxml,在mxml文件中新建一個(gè)textinput文本框用于獲取用戶輸入的內(nèi)容,button按鈕用戶發(fā)送內(nèi)容到j(luò)ava socket服務(wù)器,一個(gè)label用戶顯示向前socket狀態(tài),另一個(gè)label用于顯示從服務(wù)器返回的信息。 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.                     //連接服務(wù)器(ip,port)  
          14.                     socket = new Socket("localhost",10086);  
          15.                       
          16.                     //成功連接狀態(tài)事件  
          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.                     //服務(wù)器信息事件  
          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存放數(shù)據(jù)  
          37.                 var message:ByteArray = new ByteArray();  
          38.                 //使用UTF形式防止中文亂碼  
          39.                 message.writeUTFBytes(txt_socket.text+"\r\n");  
          40.                 //數(shù)據(jù)寫入緩沖區(qū)  
          41.                 socket.writeBytes(message);  
          42.                 //將緩沖區(qū)數(shù)據(jù)發(fā)送出去  
          43.                 socket.flush();  
          44.                 //清空文本框內(nèi)容  
          45.                 txt_socket.text = "";  
          46.             }  
          47.         ]]>  
          48.     </fx:Script>  
          49.   
          50.     <fx:Declarations>  
          51.         <!-- 將非可視元素(例如服務(wù)、值對象)放在此處 -->  
          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>  
           
          代碼編寫完成后運(yùn)行index.mxml文件,最后執(zhí)行效果就如前面【實(shí)例效果】所示。


          • 安全沙箱
          下面這段是從網(wǎng)上抄的:
          ----------------------------------------------------------------------------
          在 Adobe Flash Player 升級到 9.0.124 后,由于安全策略更改,原來 Socket 或 XmlSocket 的應(yīng)用里的 http 方式加載安全策略的手段不能繼續(xù)使用。更改如下:
          1, 首先檢測目標(biāo)服務(wù)器的 843 端口是否提供安全策略
           

          2, 如果 1 沒有檢測到策略,則檢測 actionscript 是否使用了 Security.loadPolicyFile(xmlsocket://)手段提供安全策略,如果還沒檢測到,則使用第 3 步檢測
          3, 檢測目標(biāo)服務(wù)器目標(biāo)端口是否提供安全策略。

          在說具體處理方式前,我先描述一下 Flash Player 的驗(yàn)證過程。在 Flex 程序發(fā)出 Socket 或 XmlSocket( 以下統(tǒng)稱為 Socket) 請求前, FlashPlayer 會先判斷是否為本地調(diào)用,如果不是。即用一個(gè) Socket 去鏈接到你的服務(wù)端,三次握手成功后一方面發(fā)出字符串“ <policy-file-request/>\0 “另一方面監(jiān)聽返回的安全策略。安全策略接收成功后, FlashPlayer 就斷開驗(yàn)證的 Socket ,然后再運(yùn)行程序本身的 Socket 。在整個(gè) SWF 運(yùn)行期間,無論你請求多少次,只要域相同, FlashPlayer 就只驗(yàn)證一次。這里有兩個(gè)重點(diǎn):
           
          第一個(gè)是驗(yàn)證的 Socket 和程序的 Socket 是兩個(gè) Socket 。所以你在本地測試時(shí),服務(wù)端監(jiān)聽到 N 個(gè) Socket 請求,但布置到服務(wù)端后,服務(wù)端會監(jiān)聽到 N+1 個(gè)請求。
          第二是驗(yàn)證的 Socket 發(fā)送“ <policy-file-request/>\0 “請求和接收你的策略文件是沒有先后關(guān)系的,所以你沒必要接收完“ <policy-file-request/>\0 “后才發(fā)策略文件。我的做法是只要監(jiān)聽到請求,就把策略字符串發(fā)過去。
          -----------------------------------------------------------------------------------

          那么簡單的說,如果Flex項(xiàng)目依賴其它語言的服務(wù)器的話(比如依賴J2EE服務(wù)器),在flex的socket客戶端向JavaSocket服務(wù)器發(fā)送請求之前,F(xiàn)lex會優(yōu)先發(fā)送一個(gè)安全驗(yàn)證消息,如果java服務(wù)器不返回驗(yàn)證消息則當(dāng)前socket通信失敗。
          解決辦法有很多種,我在網(wǎng)上也看了很多,但是很多寫得有問題。
          根據(jù)我多方調(diào)查,個(gè)人覺得這種方案比較靠譜:
          在Java服務(wù)器端創(chuàng)建一個(gè)端口號為843的ServerSocket監(jiān)聽Flex安全沙箱驗(yàn)證消息,如果接收到<policy-file-request/>文件信息,則向客戶端返回XMl驗(yàn)證內(nèi)容:“<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0”
          具體代碼如下:
          Java代碼  
          1. /**  
          2.  * 處理與Flex認(rèn)證的線程類  
          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>\0";   
          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.             //接收并發(fā)送Flex安全驗(yàn)證請求   
          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認(rèn)證");   
          25.                 pw.print(cross_xml);   
          26.                 pw.flush();   
          27.                 br.close();   
          28.                 pw.close();   
          29.                 socket.close();   
          30.                 System.out.println("完成policy-file-request認(rèn)證");   
          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("執(zhí)行policy認(rèn)證時(shí)發(fā)生異常",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.         //創(chuàng)建安全驗(yàn)證服務(wù)器   
          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.      * 啟動服務(wù)器  
          21.      */  
          22.     public void startPolicy(){   
          23.         new Thread(this).start();   
          24.     }   
          25.        
          26.     /**  
          27.      * 關(guān)閉服務(wù)器  
          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發(fā)送第一次Socket請求(例子里的端口號是10086)時(shí),ServerSocket843端口會收到安全沙箱驗(yàn)證,隨后server將正確的驗(yàn)證消息返回給Flex客戶端,F(xiàn)lex認(rèn)證成功后真正的10086端口Socket連結(jié)就已經(jīng)搭建了,隨后雙方就可以暢通無阻通信了(一次會話只進(jìn)行一次沙箱驗(yàn)證)。


          • Servlet啟動ServerSocket
          我通常比較喜歡創(chuàng)建一個(gè)servlet,在web.xml中配置容器啟動時(shí)運(yùn)行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>  
           
          以上一個(gè)完整的Flex+Java的Socket通信就完成了。
          主站蜘蛛池模板: 曲阜市| 依安县| 马山县| 曲水县| 邓州市| 青阳县| 临城县| 云梦县| 西宁市| 武清区| 陈巴尔虎旗| 石棉县| 崇明县| 黑山县| 中方县| 望谟县| 尼木县| 武冈市| 高唐县| 潜江市| 宜城市| 鄂伦春自治旗| 五大连池市| 游戏| 商洛市| 炎陵县| 嘉义县| 郴州市| 东乡| 浏阳市| 广平县| 安仁县| 蓝田县| 金门县| 措美县| 盐池县| 东丽区| 外汇| 呼图壁县| 青浦区| 梅河口市|