亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Flex通信-與Java實現Socket通信實例

系統 1920 0

  • 環境準備
【服務器端】
JDK1.6,“java.net”包對網絡編程提供了非常全面的支持,包括Socket
開發環境:Eclipse
【客戶端】
Flex4,”flash.net”包也提供了Socket的支持
開發環境:FlashBuilder4

  • 實例效果
我是用Java啟動一個ServerSocket作為服務器,Flex創建一個頁面,當點擊頁面上的按鈕時向Java服務器發送消息。

Flex客戶端輸入“阿里巴巴”再點擊按鈕:
Flex通信-與Java實現Socket通信實例
?Java控制臺:


?

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

Flex通信-與Java實現Socket通信實例
?

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

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

首先創建一個 SocketUtil類,用于創建ServerSocket和獲取Socket
      public class SocketUtil {
	
	/**
	 * 創建ServerSocket
	 * @param port
	 * @return
	 */
	public static ServerSocket getServerSocket(int port){
		ServerSocket server = null;
		try {
			server = new ServerSocket(port);
			System.out.println("------ServerSocket創建成功,Port:"+port);
			return server;
		} catch (IOException e) {
			if(server!=null && !server.isClosed()){
				try {
					server.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			throw new RuntimeException("創建ServerSocket時發生異常,Port:"+port,e);
		}
	}
	
	/**
	 * 獲取Socket
	 * @param server
	 * @return
	 */
	public static Socket getSocket(ServerSocket server){
		Socket socket = null;
		try {
			socket = server.accept();
			System.out.println("------Socket連接成功,IP:"+socket.getInetAddress());
			return socket;
		} catch (IOException e) {
			if(socket!=null && !socket.isClosed()){
				try {
					socket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			throw new RuntimeException("創建Socket時發送異常",e);
		}
	}
	
}
    
?
然后創建一個帶多線程的類,用于服務器與客戶端的IO通信
      public class SocketThread implements Runnable {
	private Socket socket;
	private String encoding;
	
	public SocketThread(Socket socket,String encoding) {
		this.socket = socket;
		this.encoding = encoding;
	}
	
	/**
	 * 與客戶端交互代碼
	 */
	@Override
	public void run() {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(socket
					.getInputStream(), encoding));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
					socket.getOutputStream(), encoding));
			
			String getMsg;
			while ((getMsg = br.readLine()) != null && !"exit".equalsIgnoreCase(getMsg)) {
				// 客戶端未提出"exit"命令,則循環交流
				System.out.println("From client message:" + getMsg);
				bw.append("你好[" + socket.getInetAddress() + "],服務器收到你的信息:"
						+ getMsg + "\r\n");
				bw.flush();
			}
			
			//客戶端提出"exit"請求,關閉當前socket...
			br.close();
			bw.close();
			socket.close();
			System.out.println("當前Socket連接結束......");
		} catch (Exception e) {
			if(!socket.isClosed()){
				try {
					socket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			throw new RuntimeException("Socket線程類發送異常...",e);
		}
	}
}
    
??
SocketServer類代碼
      public class SocketServer implements Runnable {
	private int port = 10086;
	private boolean status = true;
	private ServerSocket server = null;
	
	@Override
	public void run() {
		//創建Socket服務器
		server = SocketUtil.getServerSocket(port);
		while(status){
			Socket socket = SocketUtil.getSocket(server);
			new Thread(new SocketThread(socket,"UTF-8")).start();
		}
	}
	
	/**
	 * 啟動服務器
	 */
	public void startSocket(){
		new Thread(this).start();
	}
	
	/**
	 * 關閉服務器
	 */
	public void stopSocket(){
		status = false;
		if(server!=null && !server.isClosed()){
			try {
				server.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

    
?

最后在Main函數中啟動Socket服務即可:
        public static void main(String[] args) {
		new SocketServer().startSocket();
	}
      
?
  • Flex客戶端代碼
Flex端創建Socket有兩種方式:
第一種通過connect方法連接Socket服務器:
          var socket:Socket = new Socket();
socket.connect("localhost",10086);
        
?第二種通過創建Socket實例時在構造函數中傳入服務器ip和端口號連接:
          socket = new Socket("localhost",10086);
        
?Flex通過ByteArray傳送IO數據,這里有一點稍微注意一下在寫入的內容后面會加" \r\n "回車換行符,因為java端是通過BufferedReader.readLine的形式獲取一行數據,如果不換行服務器端IO就一直處于阻塞狀態:
          //ByteArray存放數據
var message:ByteArray = new ByteArray();
//使用UTF形式防止中文亂碼
message.writeUTFBytes(txt_socket.text+"\r\n");
//數據寫入緩沖區
socket.writeBytes(message);
        
?Flex有多種事件用于監聽Socket的狀態:
          Event.CONNECT:Socket與服務器成功連接時觸發的事件
Event.CLOSE:Socket與服務器斷開連接時觸發的事件
IOErrorEvent.IO_ERROR:Socket通信時發生IO錯誤時觸發的事件
ProgressEvent.SOCKET_DATA:服務器返回數據時觸發的事件
        

新建一個Flex普通項目,入口文件定義為index.mxml,在mxml文件中新建一個textinput文本框用于獲取用戶輸入的內容,button按鈕用戶發送內容到java socket服務器,一個label用戶顯示向前socket狀態,另一個label用于顯示從服務器返回的信息。 index.mxml代碼如下:
          <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="955" minHeight="600">

	<fx:Script>
		<![CDATA[
			
			
			private var socket:Socket = null;
			protected function button1_clickHandler(event:MouseEvent):void
			{
				if(socket==null || !socket.connected){
					//連接服務器(ip,port)
					socket = new Socket("localhost",10086);
					
					//成功連接狀態事件
					socket.addEventListener(Event.CONNECT,function connFun(e:Event):void{
						l_status.text = "Connect to server success...";
					});
					//連接中斷事件
					socket.addEventListener(Event.CLOSE,function closeFun(e:Event):void{
						l_status.text = "Connect to server closed...";
					});
					//連接異常事件
					socket.addEventListener(IOErrorEvent.IO_ERROR,function closeFun(e:IOErrorEvent):void{
						l_status.text = "Connect exception ..."+e.toString();
					});
					//服務器信息事件
					socket.addEventListener(ProgressEvent.SOCKET_DATA,function dataFun(e:ProgressEvent):void{
						var getMsg:ByteArray = new ByteArray;
						socket.readBytes(getMsg);
						l_result.text = getMsg.toString();
					});
				}
				
				//ByteArray存放數據
				var message:ByteArray = new ByteArray();
				//使用UTF形式防止中文亂碼
				message.writeUTFBytes(txt_socket.text+"\r\n");
				//數據寫入緩沖區
				socket.writeBytes(message);
				//將緩沖區數據發送出去
				socket.flush();
				//清空文本框內容
				txt_socket.text = "";
			}
		]]>
	</fx:Script>

	<fx:Declarations>
		<!-- 將非可視元素(例如服務、值對象)放在此處 -->
	</fx:Declarations>
	<s:Button x="156" y="56" label="按鈕" click="button1_clickHandler(event)"/>
	<s:TextInput x="20" y="56" id="txt_socket"/>
	<s:Label x="20" y="104" id="l_status"/>
	<s:Label x="234" y="65" id="l_result"/>
</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/>\0 “另一方面監聽返回的安全策略。安全策略接收成功后, FlashPlayer 就斷開驗證的 Socket ,然后再運行程序本身的 Socket 。在整個 SWF 運行期間,無論你請求多少次,只要域相同, FlashPlayer 就只驗證一次。這里有兩個重點:
?
第一個是驗證的 Socket 和程序的 Socket 是兩個 Socket 。所以你在本地測試時,服務端監聽到 N 個 Socket 請求,但布置到服務端后,服務端會監聽到 N+1 個請求。
第二是驗證的 Socket 發送“ <policy-file-request/>\0 “請求和接收你的策略文件是沒有先后關系的,所以你沒必要接收完“ <policy-file-request/>\0 “后才發策略文件。我的做法是只要監聽到請求,就把策略字符串發過去。
-----------------------------------------------------------------------------------

那么簡單的說,如果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>\0”
具體代碼如下:
      /**
 * 處理與Flex認證的線程類
 * @author Administrator
 */
public class PolicyThread implements Runnable {
	private final String policy_xml = "<policy-file-request/>";
	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";
	private Socket socket;
	
	public PolicyThread(Socket socket){
		this.socket = socket;
	}
	
	@Override
	public void run() {
		try {
			//接收并發送Flex安全驗證請求
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			PrintWriter pw = new PrintWriter(socket.getOutputStream());
			char[] by = new char[22];
			br.read(by, 0, 22);
			String s = new String(by);
			if(s.equals(policy_xml)){
				System.out.println("接收policy-file-request認證");
				pw.print(cross_xml);
				pw.flush();
				br.close();
				pw.close();
				socket.close();
				System.out.println("完成policy-file-request認證");
			}
		} catch (IOException e) {
			if(!socket.isClosed()){
				try {
					socket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			throw new RuntimeException("執行policy認證時發生異常",e);
		}
	}

}

    
      public class PolicyServer implements Runnable{
	
	private final int policy_port = 843;
	private boolean status = true;
	
	private ServerSocket server = null;
	@Override
	public void run() {
		//創建安全驗證服務器
		server = SocketUtil.getServerSocket(policy_port);
		
		while(status){
			Socket socket = SocketUtil.getSocket(server);
			new Thread(new PolicyThread(socket)).start();
		}
	}
	
	
	/**
	 * 啟動服務器
	 */
	public void startPolicy(){
		new Thread(this).start();
	}
	
	/**
	 * 關閉服務器
	 */
	public void stopPolicy(){
		status = false;
		if(server!=null && !server.isClosed()){
			try {
				server.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

    
?
Flex客戶端向Java發送第一次Socket請求(例子里的端口號是10086)時,ServerSocket843端口會收到安全沙箱驗證,隨后server將正確的驗證消息返回給Flex客戶端,Flex認證成功后真正的10086端口Socket連結就已經搭建了,隨后雙方就可以暢通無阻通信了(一次會話只進行一次沙箱驗證)。


  • Servlet啟動ServerSocket
我通常比較喜歡創建一個servlet,在web.xml中配置容器啟動時運行servlet的init方法,這樣端口號為10086和843的serverSocket就會啟動:
        public class InitServers extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public InitServers() {
        super();
    }

	/**
	 * @see Servlet#init(ServletConfig)
	 */
	public void init(ServletConfig config) throws ServletException {
		new PolicyServer().startPolicy();
		new SocketServer().startSocket();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

}

      
?web.xml

      <servlet>
		<display-name>InitServers</display-name>
		<servlet-name>InitServers</servlet-name>
		<servlet-class>socket.InitServers</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
    
?
以上一個完整的Flex+Java的Socket通信就完成了。

Flex通信-與Java實現Socket通信實例


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久热亚洲 | 成人伊人青草久久综合网 | 国产精品久久久亚洲 | 欧美日韩一级片在线观看 | 日本久久免费 | 亚洲欧美综合久久 | 日本aⅴ网站 | 久久久国产一区二区三区 | 色片在线看 | 99久久免费观看 | 欧美激情精品久久久久久久久久 | 免费aa毛片 | 国产aaaaaa | 成人午夜视频在线观看 | 婷婷亚洲综合一区二区 | 在线成人精品国产区免费 | 欧美精品a毛片免费观看 | 曰本黄色录像 | 亚洲综合激情六月婷婷在线观看 | 九九99香蕉在线视频美国毛片 | 欧美精品99 | 久久国产免费福利资源网站 | 精品国产第一国产综合精品gif | 男女一级毛片免费视频看 | 中文字幕三级在线不卡 | 亚洲欧美精品中文字幕 | 一级片视频免费看 | 国产aaaaaa| 美女羞羞视频网站 | 国产日韩一区二区三区在线播放 | 久久国产美女免费观看精品 | 91成人精品 | 日本久久久久亚洲中字幕 | 亚洲欧洲尹人香蕉综合 | 欧美骚视频| 妖精视频一区二区三区 | 久久9966精品国产免费 | 日日干影院 | 天天草天天 | 91精品国产91久久久久久 | 美女洗澡一级毛片 |