mina学习基础-入门实例-传输定长报文(三)

来源:互联网 发布:天猫数据在线直播 编辑:程序博客网 时间:2024/05/16 04:42
Apache的MINA(Multipurpose InfraStructure Networked Application)是一个网络应用框架,
它提供了一个抽象的,事件驱动的异步API,使Java NIO可以在各种传输协议(例如TCP协议和UDP协议)下高效开发.
其中无论是创建mina服务器还是客户端,最重要的三步都是:创建接收器/发送器,添加消息过滤器和添加业务处理器.
其中过滤器是mina的核心,mina提供了很多种过滤器,例如上篇笔记讲到了通过mina提供的ObjectSerializationCodecFactory过滤器传输java对象.
然而在实际项目中由于可能存在两种服务是用不同的语言实现的,例如客户端是用python实现的,那么就不能再使用ObjectSerializationCodecFactory过滤器了.
这种情况下最长用的方式是:传输定长报文,即客户端和服务器规定前n个字节放报文长度,然后客户端向服务器发包,当服务器接收到的报文长度
与预定好的长度相等时,服务器就认为是一条完成的消息.

1.开发服务器,直接看代码MinaServer.

<span style="font-size:12px;">package com.ilucky.mina.server;import org.apache.mina.filter.codec.ProtocolCodecFilter;import org.apache.mina.filter.executor.ExecutorFilter;import org.apache.mina.filter.executor.OrderedThreadPoolExecutor;import org.apache.mina.transport.socket.nio.NioSocketAcceptor;import java.net.InetSocketAddress;import java.util.concurrent.ThreadFactory;import java.util.concurrent.TimeUnit;/** * @author IluckySi * @date 20140528 */public class MinaServer {    public static final String HOST = "127.0.0.1";        private static final int PORT = 10061;        private static final int BUFFER_SIZE = 8192;        private static final ThreadFactory THREAD_FACTORY = new ThreadFactory() {        public Thread newThread(final Runnable r) {            return new Thread(null, r, "MinaThread2", 64 * 1024);        }    };    public static void main(String[] args) {    try {        //创建服务.    NioSocketAcceptor  acceptor = new NioSocketAcceptor(Runtime.getRuntime().availableProcessors() + 1);         //设置缓冲大小.        acceptor.getSessionConfig().setReceiveBufferSize(BUFFER_SIZE);                //添加线程池.        OrderedThreadPoolExecutor executor = new OrderedThreadPoolExecutor(0, 1000, 60,  TimeUnit.SECONDS, THREAD_FACTORY);        acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(executor));        //添加消息过滤器.        acceptor.getFilterChain().addLast("codec",  new ProtocolCodecFilter(new XMLProtocolCodecFactory(4)));        //添加业务处理器.        acceptor.setHandler(new MinaServerIoHandler());                   //绑定端口.        acceptor.bind(new InetSocketAddress(HOST, PORT));        System.out.println("mina server启动成功!");    } catch (Exception e) {    System.out.println("mina server启动失败!");    }    }}/**输出结果:mina server启动成功!log4j:WARN No appenders could be found for logger (org.apache.mina.filter.executor.OrderedThreadPoolExecutor).log4j:WARN Please initialize the log4j system properly.log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.服务器收到客户端返回的消息<?xml version="1.0" encoding="UTF-8"?><root><head><author>IluckySi</author><date>20140717 20:35:14</date></head></root>*/</span>

<span style="font-size:12px;">package com.ilucky.mina.server;import org.apache.mina.core.service.IoHandlerAdapter;import org.apache.mina.core.session.IoSession;/** * @author IluckySi * @date 20140528 */public class MinaServerIoHandler extends IoHandlerAdapter  { public void messageReceived(IoSession session, Object message) throws Exception {           String  msg = message.toString();           System.out.println("服务器收到客户端返回的消息" + msg);           session.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +"<root><head><result>success</result></head></root>"); }}</span>

2.开发客户端,直接看代码MinaClient.

<span style="font-size:12px;">package com.ilucky.mina.client;import java.net.InetSocketAddress;import org.apache.mina.core.future.ConnectFuture;import org.apache.mina.core.service.IoConnector;import org.apache.mina.core.session.IoSession;import org.apache.mina.filter.codec.ProtocolCodecFilter;import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;import org.apache.mina.transport.socket.nio.NioSocketConnector;/** * @author IluckySi * @date 20140507 */public class MinaClient {public static final String HOST = "127.0.0.1";public static final int PORT = 4000;public static void main(String[] args) {//创建连接器.IoConnector connector = new NioSocketConnector();  //设置超时时间.connector.setConnectTimeoutMillis(30000); //添加消息过滤器connector.getFilterChain().addLast("codec",new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));//添加业务理器.connector.setHandler(new MinaClientHandler());IoSession session = null;try {//创建连接.ConnectFuture future = connector.connect(new InetSocketAddress(HOST, PORT));// 等待连接创建完成future.awaitUninterruptibly();session = future.getSession();User user = new User();user.setUsername("IluckySi");user.setPassword("123456");session.write(user);System.out.println("客户端向服务器发送消息" + user);;} catch (Exception e) {System.out.println("客户端发送消息失败!");}//等待连接断开, 即线程阻塞在这里, 一直等到服务器关闭此session后, 线程才会继续执行.session.getCloseFuture().awaitUninterruptibly();//释放资源.connector.dispose();}}</span>
<span style="font-size:12px;">package com.ilucky.mina.client;import org.apache.mina.core.service.IoHandlerAdapter;import org.apache.mina.core.session.IoSession;/** * @author IluckySi * @date 20140507 */public class MinaClientHandler extends IoHandlerAdapter  { public void messageReceived(IoSession session, Object message) throws Exception {            String  msg = message.toString();            System.out.println("客户端收到服务器返回的消息" + msg);    }}</span>

3.开发消息解码编码器(服务器端和客户端是一样的),直接看代码:XMLProtocolCodecFactory.

<span style="font-size:12px;">package com.ilucky.mina.server;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;/** * @author IluckySi * @date 20140528 */public class XMLProtocolCodecFactory implements ProtocolCodecFactory {    private final XMLProtocolEncoder encoder;    private final XMLProtocolDecoder decoder;    public XMLProtocolCodecFactory(int socketPrefixLength) {        encoder = new XMLProtocolEncoder(socketPrefixLength);        decoder = new XMLProtocolDecoder(socketPrefixLength);    }    public ProtocolEncoder getEncoder(IoSession session) throws Exception {        return encoder;    }    public ProtocolDecoder getDecoder(IoSession session) throws Exception {        return decoder;    }}</span>
<span style="font-size:12px;">package com.ilucky.mina.server;import java.io.InputStream;import org.apache.mina.core.buffer.IoBuffer;import org.apache.mina.core.session.IoSession;import org.apache.mina.filter.codec.CumulativeProtocolDecoder;import org.apache.mina.filter.codec.ProtocolDecoderOutput;import org.dom4j.Document;import org.dom4j.io.SAXReader;/** * @author IluckySi * @date 20140528 */public class XMLProtocolDecoder extends CumulativeProtocolDecoder {    private int socketPrefixLength;    public XMLProtocolDecoder(int socketPrefixLength) {        this.socketPrefixLength = socketPrefixLength;    }    @Override    protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {    try {    //prefixedDataAvailable方法是判断得到IoBuffer里的数据是否满足一条消息了.    if (!in.prefixedDataAvailable(this.socketPrefixLength, Integer.MAX_VALUE)) {return false;}if (in == null || in.limit() == in.position() || !in.hasRemaining()) {return false;}InputStream is = in.asInputStream();is.read(new byte[this.socketPrefixLength]);SAXReader reader = new SAXReader();Document doc = reader.read(is);out.write(doc.asXML());return true;    } catch (Exception e) {    System.out.println("服务器解码失败: " + e.toString());    return false;    }    }}</span>
<span style="font-size:12px;">package com.ilucky.mina.server;import org.apache.mina.core.buffer.IoBuffer;import org.apache.mina.core.session.IoSession;import org.apache.mina.filter.codec.ProtocolEncoderAdapter;import org.apache.mina.filter.codec.ProtocolEncoderOutput;import java.nio.charset.Charset;import java.nio.charset.CharsetEncoder;/** * @author IluckySi * @date 20140528 */public class XMLProtocolEncoder extends ProtocolEncoderAdapter {    private int socketPrefixLength;    public XMLProtocolEncoder(int socketPrefixLength) {        this.socketPrefixLength = socketPrefixLength;    }    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {        CharsetEncoder charsetEncoder = Charset.forName("UTF-8").newEncoder();        String value = ((String) message);        IoBuffer buffer = IoBuffer.allocate(64);        buffer.setAutoExpand(true);        buffer.putPrefixedString(value, this.socketPrefixLength, charsetEncoder);        buffer.flip();        out.write(buffer);    }}</span>

4.测试服务器和客户端.

  先启动服务器,再启动客户端,发现客户端成功发送消息,服务器成功接收消息,并成功写回消息给客户端.

                                            点击此处下载源码,亲,免积分的哦!                                         

 
0 0