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