使用Mina设置跟服务器长链

mina是阿帕奇的一个长链框架比起我们常用的环信融云等框架功能上来说是少了一些,但是用过环信融云的开发者都知道它们打出来的包是十分巨大的,单个app只配置环信能有18M大小这对使用流量的用户来说是不容易接受的,接下来我们就介绍下mina这个轻量级框架的使用。

1.首先我们来看服务端是如何配置的
mina接收网络请求设置类是IoAcceptor它负责配置我们的mina连接属性,在介绍IoAcceptor这个类之前我们先介绍另外一个类IoHandlerAdapter这个类负责接收发送消息以及session状态的监听。

 public class DemoServerHandler extends IoHandlerAdapter {
            // 从端口接受消息,会响应此方法来对消息进行处理
            @Override
            public void messageReceived(IoSession session, Object message) throws Exception {
                super.messageReceived(session, message);
                String msg = message.toString();
                if ("exit".equals(msg)) {
                    session.close(true); // 如果客户端发来exit,则关闭该连接
                }
                // 向客户端发送消息 msg为我们服务端接收到的消息
                session.write("哈哈哈哈哈哈哈哈哈哈哈哈");
            }

            // 向客服端发送消息后会调用此方法
            @Override
            public void messageSent(IoSession session, Object message) throws Exception {
                super.messageSent(session, message);
//            session.close(true);//加上这句话实现短连接的效果,向客户端成功发送数据后断开连接
                System.out.println("服务器发送消息成功...");
            }

            // 关闭与客户端的连接时会调用此方法
            @Override
            public void sessionClosed(IoSession session) throws Exception {
                super.sessionClosed(session);
                System.out.println("服务器与客户端断开连接...");
            }

            // 服务器与客户端创建连接
            @Override
            public void sessionCreated(IoSession session) throws Exception {
                super.sessionCreated(session);
                System.out.println("服务器与客户端创建连接...");
            }

            // 服务器与客户端连接打开
            @Override
            public void sessionOpened(IoSession session) throws Exception {
                System.out.println("服务器与客户端连接打开...");
                super.sessionOpened(session);
            }

            @Override
            public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
                super.sessionIdle(session, status);
                System.out.println("服务器进入空闲状态...");
            }

            @Override
            public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
                super.exceptionCaught(session, cause);
                System.out.println("服务器发送异常...");
            }

        }

接下来就是设置service类启动IoAccepter

public class DemoServer {
    // 端口号,要求客户端与服务器端一致
    private static int PORT = 3344;

    public static void main(String[] args) {
        IoAcceptor acceptor = null;
        try {
            // 创建一个非阻塞的server端的Socket
            acceptor = new NioSocketAcceptor();
            // 设置过滤器(使用mina提供的文本换行符编解码器)
            acceptor.getFilterChain().addLast(
                    "codec",
                    new ProtocolCodecFilter(new TextLineCodecFactory(Charset
                            .forName("UTF-8"),
                            LineDelimiter.WINDOWS.getValue(),
                            LineDelimiter.WINDOWS.getValue())));
            // 自定义的编解码器
            // acceptor.getFilterChain().addLast("codec", new
            // ProtocolCodecFilter(new CharsetCodecFactory()));
            // 设置读取数据的换从区大小
            acceptor.getSessionConfig().setReadBufferSize(2048);
            // 读写通道10秒内无操作进入空闲状态
            acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
            // 为接收器设置管理服务
            acceptor.setHandler(new DemoServerHandler());
            // 绑定端口
            acceptor.bind(new InetSocketAddress(PORT));
            System.out.println("服务器启动成功... 端口号未:" + PORT);

        } catch (Exception e) {
            System.out.println("服务器启动异常...");
            e.printStackTrace();
        }

    }
}

服务器端的代码到这里就基本ok了只要运行这个代码我们就能启动服务器端了。

2.接下来就是客户端代码

A.首先我们需要一个线程来启动我们的长链服务(客户端网络请求要在非主线程中进行)
代码如下

public class MinaThread extends Thread {

    private IoSession session = null;
    private IoConnector connector = null;

    @Override
    public void run() {
        super.run();
        // "客户端链接开始..."
        connector = new NioSocketConnector();
        // 设置链接超时时间
        connector.setConnectTimeoutMillis(10000);
        // 添加过滤器
        // connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue())));
        connector.setHandler(new MinaClientHandler());
        connector.setDefaultRemoteAddress(new InetSocketAddress(ConstantUtil.WEB_MATCH_PATH, ConstantUtil.WEB_MATCH_PORT1));
        connector.addListener(new IoListener() {  // 监听客户端是否断线(断线后每隔5秒检测下连接状态如果连上了发送给服务器消息链接上了)
            @Override
            public void sessionDestroyed(IoSession arg0) throws Exception {
                super.sessionDestroyed(arg0);
                try {
                    while (true) {
                        Thread.sleep(5000);
                        System.out.println(((InetSocketAddress) connector.getDefaultRemoteAddress()).getAddress().getHostAddress());
                        ConnectFuture future = connector.connect();
                        future.awaitUninterruptibly();// 等待连接创建完成  "断线2"
                        session = future.getSession();// 获得session  "断线3"
                        if (session != null && session.isConnected()) {//(InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress()+ ":" + ((InetSocketAddress) session.getRemoteAddress()).getPort() + "]成功"
                            session.write("start");
                            break;
                        }
                    }
                } catch (Exception e) {
                    // TODO:  handle exception
                }
            }
        });

        //开始连接
        try {
            ConnectFuture future = connector.connect();
            future.awaitUninterruptibly();// 等待连接创建完成
            session = future.getSession();// 获得session
            if (session != null && session.isConnected()) {
                session.write("start");
            }//否则 "写数据失败"
        } catch (Exception e) {//"客户端链接异常..."
            e.printStackTrace();
        }
        if (session != null && session.isConnected()) {
            session.getCloseFuture().awaitUninterruptibly();// 等待连接断开
            // connector.dispose();//彻底释放Session,退出程序时调用不需要重连的可以调用这句话,也就是短连接不需要重连。长连接不要调用这句话,注释掉就OK。
        }

    }
}

这里主要就是设置了一些链接的属性以及短线重连的控制还有就是给服务器发送请求的处理

B.在此我们需要一个IoListener来监听服务端的状态以及session的状态

public class IoListener implements IoServiceListener {

    @Override
    public void serviceActivated(IoService arg0) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void serviceDeactivated(IoService arg0) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void serviceIdle(IoService arg0, IdleStatus arg1) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void sessionClosed(IoSession arg0) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void sessionCreated(IoSession arg0) throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public void sessionDestroyed(IoSession arg0) throws Exception {
        // TODO Auto-generated method stub

    }

}

这里我没做控制

C.我们还需要一个IoHandlerAdapter用来接收服务端发过来的请求


public class MinaClientHandler extends IoHandlerAdapter {

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        Log.i("TEST", "客户端发生异常");
        super.exceptionCaught(session, cause);
    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        String msg = message.toString();
        Log.i("TEST", "i客户端接收到的信息为:" + msg);
        super.messageReceived(session, message);
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        // TODO Auto-generated method stub
        super.messageSent(session, message);
    }
}

D.最后我们在Activity中启动我们的线程

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start();
    }

    public void start() {
        MinaThread mThread = new MinaThread();
        mThread.start();
    }
}

到这里我们的跟服务端的长链就完成了
参考自 http://blog.csdn.net/mcshidi/article/details/51590297

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值