淺嘗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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!