在上一篇文檔中我們已經了解了IoFilter的用法和其在Mina中的作用,作為Mina數據傳輸過程中比較重要的組件,IoFilter起到了承上啟下的作用----接收數據,編/解碼,將數據傳遞到邏輯層,當數據傳遞地到邏輯層時,IoFilter的使命就完成了,那么邏輯層的數據由誰來處理呢?如何處理的?這就是本文要講述的內容----IoHandler。
?
在介紹IoFilter的時候,文中首先是從IoFilter的結構和其在Mina中的作用談起的,最后添加了一個使用IoFilter的例子,之前我將其傳給幾個同學看時,感覺這種方式比較晦澀,應該將例子提到前面,由于時間的關系我不能在對IoFilter 的介紹做過多的修改,所以在本篇文檔中我就先以一個例子開頭,介紹IoHandler,希望這種講述方式能對你理解Mina有更多的幫助。
?
好了,言歸正傳,我們的例子還是以上篇文檔中的IoFilter的例子為基礎,在此基礎上著重突出IoHandler的作用。
ServerMain:
public class ServerMain {
public static void main(String[] args) throws IOException {
SocketAddress address = new InetSocketAddress
("localhost", 4321);
IoAcceptor acceptor = new SocketAcceptor();
IoServiceConfig config = acceptor.getDefaultConfig
();
// 配置數據的編解碼器
config.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new
ObjectSerializationCodecFactory()));
config.getFilterChain().addLast("logger", new
LoggingFilter());
// 綁定服務器端口
acceptor.bind(address, new ServerHandler());
System.out.println(" 服務器開始在 8000 端口監聽
.......");
}
}
ServerHandler:
public class ServerHandler extends IoHandlerAdapter {
// 創建會話
public void sessionOpened(IoSession session) throws
Exception {
System.out.println(" 服務器創建了會話 ");
session.write(" 服務器創建會話時發送的信息 。");
}
// 發送信息
public void messageSent(IoSession session, Object message)
throws Exception {
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
}
}
ClientMain:
public class ClientMain {
public static void main(String[] args) {
SocketAddress address = new InetSocketAddress
("localhost", 4321);
IoConnector connector = new SocketConnector();
IoServiceConfig config =
connector.getDefaultConfig();
// 配置數據的編解碼器
config.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new
ObjectSerializationCodecFactory()));
config.getFilterChain().addLast("logger", new
LoggingFilter());
// 連接到服務器
connector.connect(address, new ClientHandler());
System.out.println(" 已經連接到了服務器 " + address);
}
}
ClientHandler:
public class ClientHandler extends IoHandlerAdapter {
// 發送信息
public void messageSent(IoSession session, Object message)
throws Exception {
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
System.out.println(" 客戶端接收到的服務器的信息是 "
+ message);
}
}
?
上面給出里這個例子中的主要的代碼,當先后啟動服務器和客戶端后,服務器會在客戶端連接到服務器后發送一個字符串的消息。這個消息的發送就是在IoHandler中發送的。IoHandler在Mina中屬于業務層,這里的IoHandler更相是J2EE中的Servlet的作用,在IoHandler中你可以不用考慮底層數據的封裝和轉換,前提是你已經在IoFilter中已經完成了數據的轉換。這里需要提到的一個是,所謂數據的轉換,是指將二進制數據轉換成Java中的可用對象或者是基本類型的數據。由于網絡傳輸中傳輸的都是二進制數據,這就需要有一個專門的數據轉換層,就Mina中的編解碼器來實現這個功能。如果使用RMI,對于這個問題應該不陌生,二進制和對象之間的轉化過程其實就是對象的序列化和反序列化的過程。關于Mina中實現對象的序列化和反序列化會在后續的文檔中詳細介紹,在此不在贅述。
?
既然IoHandler是邏輯層,我們就用IoHandler實現一個簡單的邏輯實現。先聽一個小故事:一個淘氣的小孩要去KFC買漢堡,由于KFC生意比較好,人比較多,服務員忙不過來,于是KFC專門設立了一個自動售漢堡的機器,這個機器只是一個簡單的數據收發裝置,(由于漢堡的價格時常變化,所以價格會實時更新,因此該機器需要和KFC的漢堡的價格服務器相連)小朋友買漢堡時只要向機器中投入硬幣,機器就會查詢服務器,看價格是否符合,若符合,則送給小朋友一個漢堡
,若不符合則提示小朋友錢不夠,買不到這個漢堡。
?
上面是我自己虛構的一個小故事,我們先不管現實中的KFC是如何運作的,我們就當故事是真的了,那么現在這個小的項目分配給了我們,我們需要抽象出它的需求:
客戶端要向服務器發送數據,查詢價格,根據價格是否合理給出相應的顯示服務器接收客戶度的價格查詢請求,根據服務器中存儲的價格信息,返回響應的結果。
根據上面的需求,我們使用Mina來實現上面的服務器和客戶端,程序的代碼如下(完整代碼在附件中):
KFCFoodPriceHandler(服務器句柄):
public class KFCFoodPriceHandler extends IoHandlerAdapter {
// 創建會話
public void sessionOpened(IoSession session) throws
Exception {
// System.out.println(" 服務器創建了會話 ");
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
HashMap<String, Object> map = (HashMap<String,
Object>) message;
String buythings = (String) map.get("購買");
// System.out.println(" 服務器接收到的信息 " +
buythings);
if (buythings.equals("漢堡")) {
HashMap<String, Object> map2 = new
HashMap<String, Object>();
map2.put("食品", "漢堡");
map2.put("價格", 4);
session.write(map2);
} else if (buythings.equals("雞翅")) {
HashMap<String, Object> map2 = new
HashMap<String, Object>();
map2.put("食品", "雞翅");
map2.put("價格", 5);
session.write(map2);
} else {
session.write(" 該種物品已經出售完畢,謝謝
惠顧!");
}
}
}
KFCSellerHandler(客戶端句柄):
public class KFCSellerHandler extends IoHandlerAdapter {
private Integer childInputMoney_Ham = 4;
private Integer childInputMoney_Chick = 5;
// 創建會話
public void sessionOpened(IoSession session) throws
Exception {
HashMap<String, Object> map = new
HashMap<String, Object>();
map.put("購買", "漢堡");
session.write(map);
}
// 接收信息
public void messageReceived(IoSession session, Object
message)
throws Exception {
// System.out.println(" 客戶端接收到的服務器的信息是 "
// + (HashMap<String, Object>)
message);
HashMap<String, Object> priceInfor =
(HashMap<String, Object>) message;
// System.out.println("============" +
priceInfor.get("食品"));
String foodName = (String) priceInfor.get("食品");
if (foodName.equals("漢堡")) {
Integer foodPrice = (Integer) priceInfor.get
("價格");
if (foodPrice.equals
(childInputMoney_Ham)) {
System.out.println(" 您好,請收好
你的漢堡,歡迎下次光臨!");
} else {
System.out.println(" 對不起,你投
如的錢幣數量不夠,錢已經如數歸還,請收好!");
}
} else if (foodName.equals("雞翅")) {
Integer foodPrice = (Integer) priceInfor.get
("價格");
if (foodPrice.equals
(childInputMoney_Chick)) {
System.out.println(" 您好,請收好
你的漢堡,歡迎下次光臨!");
} else {
System.out.println(" 對不起,你投
如的錢幣數量不夠,錢已經如數歸還,請收好!");
}
}
}
}
?
通過上面的程序我們可以看出Mina的中業務邏輯處理都可以在IoHandler中,而不需要考慮對象的序列化和反序列化問題。關于IoHandler的簡單用法就說這么多。下面再看看與IoHandler相關的幾個中要的類。
?
按照慣例,還是先給出IoHandler及其相關類的類圖:
從上面的類圖我們可以清晰的看到IoHandler是一個接口,它有兩個子類:
IoHandlerAdpater:它只是提供了IoHandler中定義的方法體,沒有任何的邏輯處理,你可以根據你自己的需求重寫該類中的相關方法。這個類在實際的開發中使用的是較多的。我們上面寫的例子都是繼承于這個類來實現的。
SingleSessionIoHandlerDelegate:這是一個服務器和客戶端只有一個會話時使用的類,在該類的方法中沒有提供session的參數,該類在實際的開發中使用的較少,如果需要對該類進行更深入的了解,請參考Mina 1.1.7的API文檔。
?
在Mina提供的IoHandler的具體實現中,大部分的實現類都是繼承與IoHandlerApater,IoHandlerAdpater在Mina 1.1.7中的子類有三個:
ChainedIoHandler:這個類主要是用于處理IoHandler的messageReceived事件,它和IoHandlerChain配合使用。當在業務邏輯中有多個IoHandler需要處理時,你可以將你的每個IoHandler添加到IoHandlerChain中,這個和過濾器
鏈比較相似,關于IoFilter和IoHandlerChain的具體用法和區別會在后續的文檔中給出。
StreamIoHandler:該類也是用于處理IoHandler的messageReceived事件,它主要用于文件傳輸的系統中,比如FTP服務器中,如果需要對該類進行更深入的了解,請參考Mina 1.1.7的API文檔。
DemuxingIoHandler:該類主要是用于處理多個IoHandler的messageReceived,由于在TCP/IP協議的數據傳輸中會出現數據的截斷現象(由于socket傳輸的數據包的長度是固定的,當數據包大于該長度,數據包就會被截斷),所以提供這個類主要是保證IoHandler所處理的數據包的完整性,這個和編解碼器中的CumulativeProtocolDecoder類似,關于這兩個類的具體介紹會在后續的文檔中給出。
?
至此,關于IoHandler的作用就講述完了,希望對你能有所幫助。:)
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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