import handler.MainHandler;
import java.net.InetSocketAddress;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import coder.buffer.BufferCoderFactory;
/**
* @author duwei
* @since 2013.10.25
* <li>The main thread of mina server
* */
public class MainServer extends Thread{
//the mina info
public boolean isAlive = true;
public MainHandler handler;
public NioSocketAcceptor socketAcceptor;
public final int port = 8005;
//database info
public static String dbHost="192.168.1.103",dbName="test",username="work",password="123456";
public static int dbPort = 3306;
public MainServer(){
super("MainServer");
socketAcceptor = new NioSocketAcceptor();
socketAcceptor.setReuseAddress(true);
socketAcceptor.getSessionConfig().setKeepAlive(true);
handler = new MainHandler();
socketAcceptor.setHandler(handler);
//設置過濾器
DefaultIoFilterChainBuilder chain = socketAcceptor.getFilterChain();
chain.addLast("codec", new ProtocolCodecFilter(new BufferCoderFactory()));//明碼字符串
//啓動數據庫
startDataBaseDriver(dbHost, dbPort, dbName, username, password);
}
public void run(){
while(isAlive){
try {
sleep(3000);
} catch (Exception e) {
// TODO: handle exception
}
}
System.exit(0);
}
private void startDataBaseDriver(String host,int port,String dbName,String username,String password){
try {
} catch (Exception e) {
e.printStackTrace();
}
}
public void startAcceptor(){
try {
socketAcceptor.bind(new InetSocketAddress(port));
this.start();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
//start mina and database
MainServer main = new MainServer();
main.startAcceptor();
System.out.println("server started finished @ 192.168.1.122:8005");
}
}
從上述代碼中可見,需要建立一個編解碼工廠和一個實現IOHandler接口的實例啦,因爲IOHandler接口是負責處理所有業務邏輯的啦。
-
所謂編解碼工廠,就是一個負責在發送數據的最後階段和接收數據的最開始階段處理所發送和接收的數據。
比如:服務端發送一段數據是:“數據長度(4字節)+實際數據”,那麼接收到數據後就會首先讀取4個字節的長度信息驗證後面的實際數據有木有這麼多。完了再從IoBuffer裏解析出來寫入ProtocolDecoderOutput裏。發送數據也是類似,在session.write("...");發送數據後,會進入ProtocolEncoder實例裏對數據經行封裝。比如說加密,加壓等操作。
java代碼:
package coder.buffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
public class BufferCoderFactory implements ProtocolCodecFactory {
private ProtocolEncoder encoder;
private ProtocolDecoder decoder;
@Override
public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
decoder = new BufferDecoder();
return decoder;
}
@Override
public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
encoder = new BufferEncoder();
return encoder;
}
}
編碼類:
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
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
package coder.buffer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
public class BufferEncoder implements ProtocolEncoder{
private final AttributeKey DEFLATER = new AttributeKey(getClass(), "deflater");
private static int buffersize = 1024;
public void encode(IoSession session, Object in, ProtocolEncoderOutput out)
throws Exception{
if(in instanceof String){
byte[] bytes = ((String) in).getBytes("utf-8");
System.out.println("壓縮前:"+bytes.length);
bytes = compress(session, bytes);
System.out.println("壓縮後:"+bytes.length);
IoBuffer buffer = IoBuffer.allocate(bytes.length + 4);
buffer.putInt(bytes.length);
buffer.put(bytes);
buffer.flip();
session.write(buffer);
buffer.free();
}else{
System.out.println("message is not a String instance.");
}
}
private byte[] compress(IoSession session,byte[] inputs){
Deflater deflater = (Deflater)session.getAttribute(DEFLATER);
if(deflater == null){
deflater = new Deflater();
session.setAttribute(DEFLATER,deflater);
}
deflater.reset();
deflater.setInput(inputs);
deflater.finish();
byte[] outputs = new byte[0];
ByteArrayOutputStream stream = new ByteArrayOutputStream(inputs.length);
byte[] bytes = new byte[buffersize];
int value;
while(!deflater.finished()){
value = deflater.deflate(bytes);
stream.write(bytes,0, value);
}
outputs = stream.toByteArray();
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
return outputs;
}
public void dispose(IoSession paramIoSession)
throws Exception{
}
}
解碼類
package coder.buffer;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
public class BufferDecoder implements ProtocolDecoder{
public static final int MAX_MSG_SIZE = 5000;
public void decode(IoSession paramIoSession, IoBuffer in, ProtocolDecoderOutput out)
throws Exception{
if (in.prefixedDataAvailable(4, MAX_MSG_SIZE)) {
int length = in.getInt();
byte[] bytes = new byte[length];
in.get(bytes);
out.write(bytes);
} else {
}
}
@Override
public void dispose(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void finishDecode(IoSession arg0, ProtocolDecoderOutput arg1)
throws Exception {
// TODO Auto-generated method stub
}
}
2.編碼完成後,數據就會交給IOHandler來處理啦,這裏可以選擇繼承IoHandlerAdapter類來寫。。
IOHandler接口的幾個重要方法介紹:
sessionCreated:一個連接被創建時觸發;
sessionOpened:一個連接被打開時觸發;
sessionClosed:一個連接被關閉時觸發;
exceptionCaught:連接出現異常未被捕獲時觸發;
messageReceived:連接收到消息時觸發。
好了,接下來實現自己的Handler實例:
package handler;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
public class MainHandler extends IoHandlerAdapter{
public void sessionOpened(IoSession session) throws Exception {
System.out.println("session opened "+session.getRemoteAddress().toString());
}
public void messageReceived(IoSession session, Object message) throws Exception{
String str = new String((byte[]) message, "utf8");
//收到客戶端發來的數據
System.out.println("received message: "+str);
//向客戶端發送數據
session.write("fuck you too.");
}
public void sessionClosed(IoSession session) throws Exception {
System.out.println("session closed "+session.getRemoteAddress().toString());
}
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
System.out.println("exceptionCaught");
cause.printStackTrace();
}
}