淺嘗apache mina
This is apache-mina-2.0.4
這是使用Mina2編寫的服務端主類MyServer.java
package com.mina.server; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.charset.Charset; import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.LineDelimiter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; /** * 簡單Mina Server示例 * @see 非阻塞I/O是JDK5.0提供的API,意思是服務器不用像以前那樣調用accept()方法,阻塞等待了 * @see 開發一個Mina應用,簡單的說:就是創建連結、設定過濾規則、編寫自己的消息處理器這三步 * @see Mina執行流程:進入IoService-->IoProcessor-->IoFilter-->IoHandler-->IoFilter-->IoProcessor-->IoService */ public class MyServer { public static void main(String[] args) throws IOException { //指定服務器端所綁定的端口 int bindPort = 9876; //初始化服務端的TCP/IP的基于NIO的套接字 //即創建非阻塞服務器端,類似于Java中的ServerSocket IoAcceptor acceptor = new NioSocketAcceptor(); //調用IoSessionConfig設置讀取數據的緩沖區大小、讀寫通道均在10秒內無任何操作就進入空閑狀態 acceptor.getSessionConfig().setReadBufferSize(2048); acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); /** * 定義攔截器:可以包括日志輸出、黑名單過濾、數據的編碼(write方向)與解碼(read方向)等功能 * 其中數據的encode與decode是最為重要的,也是在使用Mina時最主要關注的地方 */ //啟用Mina的日志跟蹤 acceptor.getFilterChain().addLast("logger", new LoggingFilter()); //這段代碼要在acceptor.bind()方法之前前執行,因為綁定套接字之后,就不能再做這些準備工作了 //這里所要傳輸的是以換行符為標識的數據,所以使用了Mina自帶的換行符編解碼器工廠 //若不清楚操作系統或Telnet軟件的換行符是什么,可以刪掉new TextLineCodecFactory(*,*,*)的后兩個參數 //即new TextLineCodecFactory(Charset.forName("UTF-8")),此時使用的就是TextLineCodec內部的自動識別機制 //acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory( Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue()))); /** * 指定服務器端的消息處理器。它負責編寫業務邏輯,即接收、發送數據的地方 */ //把編寫好的IoHandler注冊到IoService。它也要在acceptor.bind()方法之前前執行 acceptor.setHandler(new ServerHandler()); //綁定端口,啟動服務器 //該接口中的void bind()方法用于監聽端口、void unbind()方法用于解除對套接字的監聽 //這里與傳統的Java中的ServerSocket不同的是:IoAcceptor可以多次調用bind()方法同時監聽多個端口 //或者在一個方法中傳入多個SocketAddress參數,來監聽多個端口 acceptor.bind(new InetSocketAddress(bindPort)); System.out.println("MinaServer is startup, and it`s listing on := " + bindPort); } }
這是我們編寫的服務端消息處理器ServerHandler.java
package com.mina.server; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; /** * 自定義的消息處理器,必須實現IoHandlerAdapter類 * @see IoHandlerAdapter:它定義的方法用于處理程序接收到的消息,并處理通信中的連結,斷開,消息到達等事件 * @see 客戶機和服務器端創建后,都有一個setHandler方法,就是要傳入我們重寫的該類的對象 * @see 其中各個方法在通信中會根據情況自動調用,類似于Swing事件中的調用機制 */ public class ServerHandler extends IoHandlerAdapter { //這是IoHandlerAdapter類中最重要的一個方法。IoSession代表與對方機器的TCP/IP連接,Object代表接收到的數據 @Override public void messageReceived(IoSession session, Object message) throws Exception { String str = message.toString(); //我們已設定了服務器解析消息的規則是一行一行讀取,這里就可轉為String System.out.println("The message received from Client is [" + str + "]"); } @Override public void sessionOpened(IoSession session) throws Exception{ System.out.println("InComing Client:" + session.getRemoteAddress()); } }
這是我們編寫的客戶端主類MyClient.java
package com.mina.client; import java.net.InetSocketAddress; import java.nio.charset.Charset; import org.apache.mina.core.service.IoConnector; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.LineDelimiter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.transport.socket.nio.NioSocketConnector; /** * 簡單的TCPClient * @see Mina中的Server端和Client端的執行流程是一樣的,唯一不同的是IoService的Client端實現是IoConnector * @see 這里我們實現Mina中的TCPClient。運行MyClient時,會發現MyServer控制臺輸入如下語句 * @see The message received from Client is [豈曰無衣..] * @see The message received from Client is [月照溝渠....] * @see 說明服務器端收到的是兩條消息,因為我們所用的編解碼器是以換行符判斷數據是否讀取完畢的 */ public class MyClient { public static void main(String[] args) { //Create TCP/IP connector //NioSocketConnector功能類似于JDK中的Socket類,它也是非阻塞的讀取數據 IoConnector connector = new NioSocketConnector(); connector.setConnectTimeoutMillis(3000); connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory( Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue()))); //注冊IoHandler,即指定客戶器端的消息處理器 connector.setHandler(new ClientHandler("豈曰無衣..\r\n月照溝渠....")); //連接到服務器 //ConnectFuture connect(SocketAddress arg0,SocketAddress arg1) //該方法用于與Server端建立連接,第二個參數若不傳遞則使用本地的一個隨機端口訪問Server端 //該方法是異步執行的,且可以同時連接多個服務端 connector.connect(new InetSocketAddress("127.0.0.1", 9876)); System.out.println("Mina Client is startup"); } }
最后是我們編寫的客戶端消息處理器ClientHandler.java
package com.mina.client; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; public class ClientHandler extends IoHandlerAdapter { private final String values; public ClientHandler(String values){ this.values = values; } @Override public void sessionCreated(IoSession session) throws Exception { System.out.println("sessionCreated is invoked...."); } /** * 發送消息 * @see ================================================================================================= * @see 客戶端連接有兩個事件:sessionCreated和sessionOpened * @see sessionCreated是由IoProcessor線程觸發的,sessionOpened跟在其后,是由業務線程觸發的 * @see 由于Mina中的IoProcessor線程非常少,因此sessionCreated通常用于處理耗時短的操作 * @see 而將業務初始化等功能放在sessionOpened事件中,比如發送消息 * @see ================================================================================================= * @see 我們可以在sessionOpened()、messageReceived()中使用IoSession.write()方法發送消息 * @see 因為在這兩個方法中,TCP連接都是打開的狀態,只不過發送的時機不同 * @see sessionOpened()是在TCP連接建立之后,接收到數據之前發送 * @see messageReceived()是在接收到數據之后發送 * @see ================================================================================================= */ @Override public void sessionOpened(IoSession session) throws Exception { session.write(values); //寫數據,該操作是異步的 } /** * 關于TCP連接的關閉 * @see 無論在客戶端還是服務端,IoSession都用于表示底層的一個TCP連接 * @see 那么你會發現無論是Server端還是Client端的IoSession調用close()后,TCP連接雖然顯示關閉,但主線程仍在運行,即JVM并未退出 * @see 這是因為IoSession的close()僅僅是關閉了TCP的連接通道,并沒有關閉Server端和Client端的程序 * @see 此時需要調用IoService.dispose()停止Server端和Client端 */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println("與" + session.getRemoteAddress() + "通信過程中出現錯誤:[" + cause.getMessage() + "]..連接即將關閉...."); //關閉IoSession,該操作也是異步的....true表示立即關閉,false表示所有寫操作都flush后關閉 session.close(false); //IoSession.IoService getService()用于返回與當前會話對象關聯的IoService實例 session.getService().dispose(); } }
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!