mina 框架java服務端的搭建和通訊。

起一個好聽的名字發表於2016-06-24

建立Java專案,匯入mina包。mina下載地址:http://mina.apache.org/

不會用mina的請各種百度谷歌吧。。

新建MainServer.java類,繼承於Thread並實現main函式。

然後就在MainServer類裡搭建main結構啦。


類如下:

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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介面是負責處理所有業務邏輯的啦。

  1. 所謂編解碼工廠,就是一個負責在傳送資料的最後階段和接收資料的最開始階段處理所傳送和接收的資料。

比如:服務端傳送一段資料是:“資料長度(4位元組)+實際資料”,那麼接收到資料後就會首先讀取4個位元組的長度資訊驗證後面的實際資料有木有這麼多。完了再從IoBuffer裡解析出來寫入ProtocolDecoderOutput裡。傳送資料也是類似,在session.write("...");傳送資料後,會進入ProtocolEncoder例項裡對資料經行封裝。比如說加密,加壓等操作。

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
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{
        
   }
}

解碼類:

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
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例項:

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
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();
    }
}

好了,目前這個沒有連線資料庫的mina服務端就算是勉強搭建好了,執行一下試試??

和你的客戶端勾兌一下,看看有木有勾搭上~~ 哈哈~~

本人新手,也不太熟悉java服務端。。

如果有什麼問題,麼見怪哈。大家一起探討,一起研究,一起進步。~~

相關文章