hibernate系列學習階段到此結束了,那麼緊接着進入apache mina的開發學習,很多童鞋在微薄和qq中疑問himi為什麼突然脫離遊戲開發了,嘿嘿,其實可能更多的童鞋已經看出來了,himi在偏向伺服器server端開發了,hibernate、mysql等都是為了server端mina開發而做的鋪墊,目前的apache mina才是himi真正的目的。哈哈。himi的技術目标是“一個人能做出一個網遊~”,ok.不多說其他的了,開始himi的apache mina開發之旅吧。
對于apache mina不太連接配接的童鞋,請移步到如下百度百科連接配接進行學習了解:
<a href="http://baike.baidu.com/view/2668084.htm" target="_blank">http://baike.baidu.com/view/2668084.htm </a>
首先建立一個new project(server端),這裡himi使用ide是 eclipse;
ok,首先我們這裡先配置下環境:對于mina的日志輸出使用的是slf4j,對于slf4j在開發hibernate的時候已經很熟悉了,不需要再介紹了。另外一方面就是加入mina的core核心jar包;
1. mina-core.jar 2. slf4j-api.jar 3.slf4j-simple.jar
然後我們首先建立兩個類:
himiobject.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @author himi
*/
import java.io.serializable;
public class himiobject implements serializable{
public himiobject(int id,string name){
this.id=id;
this.name=name;
}
private int id;
private string name;
public int getid() {
return id;
public void setid(int id) {
this.id = id;
public string getname() {
return name;
public void setname(string name) {
this.name = name;
這個類是個消息object,它用于server與client端的互動的資料,它需要序列化,是以我們使用serializable接口;至于在mina架構中起到什麼作用這個後續來說;
clientminaserverhanlder.java
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import org.apache.mina.core.service.iohandleradapter;
import org.apache.mina.core.session.idlestatus;
import org.apache.mina.core.session.iosession;
public class clientminaserverhanlder extends iohandleradapter {
private int count = 0;
// 當一個新用戶端連接配接後觸發此方法.
public void sessioncreated(iosession session) {
system.out.println("新用戶端連接配接");
// 當一個客端端連結進入時 @override
public void sessionopened(iosession session) throws exception {
count++;
system.out.println("第 " + count + " 個 client 登陸!address: : "
+ session.getremoteaddress());
// 當用戶端發送的消息到達時:
@override
public void messagereceived(iosession session, object message)
throws exception {
// // 我們己設定了伺服器解析消息的規則是一行一行讀取,這裡就可轉為string:
// string s = (string) message;
// // write the received data back to remote peer
// system.out.println("收到客戶機發來的消息: " + s);
// // 測試将消息回送給用戶端 session.write(s+count); count++;
himiobject ho = (himiobject) message;
system.out.println(ho.getname());
ho.setname("serverhimi");
session.write(ho);
// 當資訊已經傳送給用戶端後觸發此方法.
public void messagesent(iosession session, object message) {
system.out.println("資訊已經傳送給用戶端");
// 當一個用戶端關閉時
public void sessionclosed(iosession session) {
system.out.println("one clinet disconnect !");
// 當連接配接空閑時觸發此方法.
public void sessionidle(iosession session, idlestatus status) {
system.out.println("連接配接空閑");
// 當接口中其他方法抛出異常未被捕獲時觸發此方法
public void exceptioncaught(iosession session, throwable cause) {
system.out.println("其他方法抛出異常");
本類主要是繼承iohandleradapter并且重寫其類的一些函數,至于每個函數的作用himi都已經在代碼中加以注視;本類的作用:
此類是用以處理消息的也可說是個消息處理器,當用戶端有消息傳給server端的時候,或者server端傳遞給client端的時候(client端也會有個消息處理器)都會通過消息處理器進行處理。
ok,下面我們來書寫server端的main函數類:
import java.io.ioexception;
import java.net.inetsocketaddress;
import org.apache.mina.core.filterchain.defaultiofilterchainbuilder;
import org.apache.mina.filter.codec.protocolcodecfilter;
import org.apache.mina.filter.codec.serialization.objectserializationcodecfactory;
import org.apache.mina.transport.socket.socketacceptor;
import org.apache.mina.transport.socket.nio.niosocketacceptor;
public class minaserver {
* @param args
public static void main(string[] args) {
//建立一個非阻塞的server端socket ,用nio
socketacceptor acceptor = new niosocketacceptor();
/*---------接收字元串---------*/
// //建立一個接收資料過濾器
// defaultiofilterchainbuilder chain = acceptor.getfilterchain();
// //設定過濾器一行行(/r/n)的讀取資料
// chain.addlast("mychin", new protocolcodecfilter(new textlinecodecfactory() ));
/*---------接收對象---------*/
//建立接收資料的過濾器
defaultiofilterchainbuilder chain = acceptor.getfilterchain();
//設定這個過濾器将以對象為機關讀取資料
protocolcodecfilter filter= new protocolcodecfilter(new objectserializationcodecfactory());
chain.addlast("objectfilter",filter);
//設定伺服器消息處理器
acceptor.sethandler(new clientminaserverhanlder());
//伺服器綁定的端口
int bindport = 9988;
//綁定端口,啟動伺服器
try {
acceptor.bind(new inetsocketaddress(bindport));
} catch (ioexception e) {
system.out.println("mina server start for error!"+bindport);
e.printstacktrace();
system.out.println("mina server run done! on port:"+bindport);
ioservice 是負責底層通訊接入,而 iohandler 是負責業務處理的。那麼 mina 架構圖中的 iofilter 作何用途呢?答案是你想作何用途都可以。但是有一個用途卻是必須的,那就是作為 ioservice 和 iohandler 之間的橋梁。iohandler 接口中最重要的一個方法是 messagereceived,這個方法的第二個參數是一個 object 型的消息,總所周知,object 是所有 java 對象的基礎,那到底誰來決定這個消息到底是什麼類型呢?這個取決于我們後面設定的過濾器!
對于在mina中建立一個server,步驟如下:
1. 建立一個sockeracceptor ,除了啟動server之外它還可以為我們可以生成過濾器defaultiofilterchainbuilder、設定消息處理器等功能;
2.設定過濾器
3. 設定消息處理器
其實很容易不是麼? 哈哈;
ok,這裡多說一些:
對于消息處理器 defaultiofilterchainbuilder,它的作用是用于設定收發的形式,例如:
//建立一個接收資料過濾器
//設定過濾器一行行(/r/n)的讀取資料
chain.addlast("mychin", new protocolcodecfilter(new textlinecodecfactory() ));
這樣設定一個過濾器作用是将來自用戶端輸入的資訊轉換成一行行的文本後傳遞給 iohandler,是以我們可以在 messagereceived 中直接将 msg 對象強制轉換成 string 對象。
ps.而如果我們不提供任何過濾器的話,那麼在 messagereceived 方法中的第二個參數類型就是一個 byte 的緩沖區,對應的類是 org.apache.mina.common.bytebuffer。雖然你也可以将解析用戶端資訊放在 iohandler 中來做,但這并不是推薦的做法,使原來清晰的模型又模糊起來,變得 iohandler 不隻是業務處理,還得充當協定解析的任務。
mina自身帶有一些常用的過濾器,例如loggingfilter(日志記錄)、blacklistfilter(黑名單過濾)、compressionfilter(壓縮)、sslfilter(ssl加密)等。
當我們設定如下:
這樣以來我們server可以收發object對象啦;
這裡是設定消息處理器,綁定在我們的clientminaserverhanlder類上,其實mina對于收發處理已經完全交給開發者來進行處理,是以至于在消息處理器如何編寫和處理就放任不會管了;
ok,現在我們可以run一下啟動server端了;
當然我們現在也可以來測試了,目前我們還沒有書寫client端的代碼,是以我們使用terminal終端進行測試,ok,打開你的terminal
然後輸入 telnet localhost 9988
觀察伺服器列印:

ok,沒有任何問題;但是這時候大家不要在終端書寫内容給server,因為我們server的消息處理器中的接受client的函數中做了如下處理:
himi這裡server處理client端發來的資料處理函數(如上代碼)中,當client發送資料過來的時候,将消息message強制轉換成了一個himiobject對象,然後改個name重寫發給client端,但是由于client端是使用終端模拟登陸根本無法接受這個對象,是以會出異常;
但是到這裡大家應該懂得,himiobject類的作用了;哈哈
下面我們來書寫client用戶端,對于建立一個client端,其實步驟雷同,步驟如下:
1 . 建立一個niosocketconnector對象;
2. 設定過濾器
3. 設定消息處理器
代碼如下:
import org.apache.mina.core.future.connectfuture;
import org.apache.mina.transport.socket.nio.niosocketconnector;
public class mainclient {
// 建立一個tcp/ip 連接配接
niosocketconnector connector = new niosocketconnector();
// //建立接收資料的過濾器
// defaultiofilterchainbuilder chain = connector.getfilterchain();
// // 設定這個過濾器将一行一行(/r/n)的讀取資料
// chain.addlast("mychin", new protocolcodecfilter(
// new textlinecodecfactory()));
// 建立接收資料的過濾器
defaultiofilterchainbuilder chain = connector.getfilterchain();
// 設定這個過濾器将以對象為機關讀取資料
protocolcodecfilter filter = new protocolcodecfilter(
new objectserializationcodecfactory());
// 設定伺服器端的消息處理器:一個samplminaserverhandler對象,
// 設定伺服器端的消息處理器:一個 samplminaserverhandler 對象,
connector.sethandler(new clientminaserverhanlder());
// set connect timeout.
connector.setconnecttimeoutcheckinterval(30);
// 連結到伺服器:
connectfuture cf = connector.connect(new inetsocketaddress("localhost",
9988));
// wait for the connection attempt to be finished.
cf.awaituninterruptibly();
cf.getsession().getclosefuture().awaituninterruptibly();
connector.dispose();
不多說了,很eazy:那麼我們繼續看clent端的消息處理器以及himiobject:
clentminaserverhanlder:
// 當一個客端端連結到伺服器後
// session.write("我來啦........");
himiobject ho = new himiobject(1,"himi");
system.out.println("i'm client &amp;&amp; i closed!");
// 當伺服器端發送的消息到達時:
// // 我們己設定了伺服器解析消息的規則是一行一行讀取,這裡就可轉為 string:
// system.out.println("伺服器發來的收到消息: " + s);
// // 測試将消息回送給用戶端 session.write(s);
client的himiobject與伺服器server的himiobejct類一模一樣!
可能有童鞋不了解為什麼server端與client的himiobject一模一樣,這裡himi說下,通過client端的消息處理器可以看出,當我們client端連接配接到伺服器後,首先會寫給server端一個himiobject對象!那麼伺服器之前說過了,接受到client端的消息後首先将消息強制轉換成himiobject對象然後處理;
既然client端發的是object,那麼當然我們的伺服器也要有對應的此object對象才可以,否則如何擷取這個object? 大家應該很容易了解;
ok,不多說直接運作client端,觀察結果:
ok,結果正常。
client與server消息邏輯如下:
1. client->傳遞himiobject給server
2. server端接受message強制轉換himiobject,并且設定其name為serverhimi,然後再傳遞給client
3. 用戶端接受message強制轉換himiobject,然後擷取此類的name列印出來!