初识mina
来源:互联网 发布:oppor11网络模式在哪 编辑:程序博客网 时间:2024/06/06 03:14
最近在看郭霖大神的慕课网视频学习mina框架,把学习的情况记录下来,方便以后查阅。
网上关于mina详细介绍很多,我就不班门弄斧了。一边看视频一边慢慢更新。
这次把注释放到代码里面,更加细致。
官网下载mina的jar包,先只导入mina-core-x.x.x.jar和slf4j-api-x.x.x.jar(mina日志打印包,不导入会报错)。
使用mina最基本的功能只需要四步。
主函数类
public class MinaServer { public static void main(String[] args) { try { NioSocketAcceptor acceptor = new NioSocketAcceptor(); /* * 自己定义Handler对象来处理消息 */ acceptor.setHandler(new MyServerHandler()); /* * 获取拦截器来过滤信息 * 添加新的拦截器 * MyTextLineFactory()是自己定义的拦截器 */ acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MyTextLineFactory())); /* * 定义idle,即设置连接多久无消息收发为进入空闲状态 * 第一个参数IdleStatus.BOTH_IDLE为多久没有读取且没有收到向客户端发送消息 * 第二个参数是设置时间,单位是秒。每隔60秒再次输出表示你又进入空闲状态 */ acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60); /* * 绑定一个端口 */ acceptor.bind(new InetSocketAddress(9090)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
自定义MyserverHandler类
public class MyServerHandler extends IoHandlerAdapter { /** * 网络异常的时候调用方法 */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { System.out.println("exceptionCaught"); } /** * 接收到消息的时候调用方法 */ @Override public void messageReceived(IoSession session, Object message) throws Exception { String s = (String)message; System.out.println("messageReceived : " + s); } /** * 发出消息的时候调用方法 */ @Override public void messageSent(IoSession session, Object message) throws Exception { System.out.println("messageSent"); } /** * 客户端会话关闭时调用的方法 */ @Override public void sessionClosed(IoSession session) throws Exception { System.out.println("sessionClosed"); } /** * 客户端会话开启的时候调用的方法 */ @Override public void sessionCreated(IoSession session) throws Exception { System.out.println("sessionCreated"); } /** * 客户端进入空闲状态的时候调用的方法 */ @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { System.out.println("sessionIdle"); } /** * 会话打开的时候调用的方法 */ @Override public void sessionOpened(IoSession session) throws Exception { System.out.println("sessionOpened"); }}
继承于IoHandlerAdapter类,实现里面的几个方法,将log打印出来、
自定义拦截器来拦截收发消息
public class MyTextLineFactory implements ProtocolCodecFactory { //自定义加码类 private MyTextLineEncoder mEncoder; //自定义解码类 private MyTextLineDecoder mDecoder; //自定义防止数据丢失解码类 private MyTextLineCumulativeDecoder mCumulativeDecoder; public MyTextLineFactory() { mEncoder = new MyTextLineEncoder(); mDecoder = new MyTextLineDecoder(); mCumulativeDecoder = new MyTextLineCumulativeDecoder(); } public ProtocolDecoder getDecoder(IoSession arg0) throws Exception { //返回的是防丢失的Decoder return mCumulativeDecoder; } public ProtocolEncoder getEncoder(IoSession arg0) throws Exception { return mEncoder; }}
你可以用mina中定义的,不过为了适应自己的需要,还是自己定义比较好。
新建一个MyTextLineFactory继承于ProtocolCodecFactory。
在MyTextLineFactory中,使用了自定义的加解码器来实现收发数据的加解码。
自定义编码类来给数据加码
public class MyTextLineEncoder implements ProtocolEncoder { public void dispose(IoSession arg0) throws Exception { } public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception { String s = null; if(message instanceof String) { s = (String)message; } //开始转码操作 if(s != null) { /* * 将字符串进行编码,采取系统默认的编码方式 * 为了提高效率(因为每一次都要获取系统默认的编码方式),这里采取一个判断 * * 类似于ListView的ViewHoder * 如果session中没有获取到属性 encoder,那么就创建一个为系统默认编码的加密方式 * 如果有的话就使用之前就有的,这样的方法可以提高运行效率 */ CharsetEncoder charsetEncoder = (CharsetEncoder)session.getAttribute("encoder"); if(charsetEncoder == null) { charsetEncoder = Charset.defaultCharset().newEncoder(); session.setAttribute("encoder", charsetEncoder); } //mina框架中开辟内存 IoBuffer ioBuffer = IoBuffer.allocate(s.length()); //设置内存可以自动开辟内存 ioBuffer.setAutoExpand(true); //设置put数据类型为系统本身的格式 ioBuffer.putString(s,charsetEncoder); ioBuffer.flip(); //写出数据 out.write(ioBuffer); } }}
最后定义解码器,将收到的字节码转化为字符串
public class MyTextLineCumulativeDecoder extends CumulativeProtocolDecoder{ /** * 当且仅当数据读取完的时候返回true * 如果没有读取完想要下次再进行读取的时候就返回false */ @Override protected boolean doDecode(IoSession session, IoBuffer ioBuffer, ProtocolDecoderOutput out) throws Exception { //开始读取的位置 int startPosition = ioBuffer.position(); //判断ioBuffer里面是否还有字节可以读取 while(ioBuffer.hasRemaining()) { byte b = ioBuffer.get(); if(b == '\n') { //读取到 '\n'的时候的位置记录下来 int currentPosition = ioBuffer.position(); //当前的总长度 int limit = ioBuffer.limit(); //把初始位置定在字符串开始的第一个字节上 ioBuffer.position(startPosition); //limit是终点的的位置,这里就是读到currentPosition的地方 //从startPosition到currentPosition位置,就是读取到'\n'的总长度 ioBuffer.limit(currentPosition); //截取从startPosition位置到currentPosition位置的所有字节,返回的是一个IoBuffer IoBuffer sliceIoBuffer = ioBuffer.slice(); //把字节码转换成字符串 byte [] dest = new byte[sliceIoBuffer.limit()]; sliceIoBuffer.get(dest); String str = new String(dest); //写出数据 out.write(str); /* * 因为在之间重定位在startPosition的位置,如果我们不重新定位到当前位置的话, * 就会一直从 startPosition -> currentPosition不停的循环导致死循环 * 这里要把开始位置定义到currentPosition */ ioBuffer.position(currentPosition); ioBuffer.limit(limit); return true; } } //如果没有读取完就要把position重新读取到开始的位置 ioBuffer.position(startPosition); return false; }}这里选择继承的是CumulativeProtocalDecoder类,这个类和ProtocalDecoder的区别在于decode方法有一个返回值,这个返回值是在循环读取的时候判断是否读取完成整个字节。如果是完全读取就返回一个true。否则就返回一个false,并且将position定位在开始的位置重新读取。
以上是服务器端的代码,下面是客户端的代码。
写一些简简单单测试的代码测试是否能联通。
public class MinaClient { public static void main(String[] args) throws Exception{ NioSocketConnector connector = new NioSocketConnector(); connector.setHandler(new MyClientHandler()); connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory())); ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1",9090)); //阻塞连接,直到连接上服务器 future.awaitUninterruptibly(); //当连接上后会返回一个IoSession对象,有这个对象可以完成许多事情 IoSession ioSession = future.getSession(); //获取从控制台输入的流 BufferedReader readIn = new BufferedReader(new InputStreamReader(System.in)); String inputContent; //当不输入bye的时候就发送输出的内容 while(!(inputContent = readIn.readLine()).equals("bye")) { ioSession.write(inputContent); } }}
首先还是导入那两个包
客户端的代码和服务端的代码差不多。从控制台输出数据,服务器能够接受到数据。
其中new MyClientHandler()中的代码与服务器中的MyServerHandler是一样的,只是改了名字而已。
这样就完成了一个简单的客户端和服务器连接的例子
1 0
- 初识mina
- 初识mina
- 初识Mina框架
- Mina初识(一)
- Mina初识(二)
- MINA
- mina
- MINA
- mina
- mina
- MINA
- mina
- Mina
- 【mina】mina传输对象
- 初识
- 初识
- 初识
- MINA JAVA
- HSF 入门-发布和调用hsf服务
- 【LeetCode】118. Pascal's Triangle
- 【Java】容器
- Ubuntu下Chrome浏览器不能以根用户身份运行的解决方法
- 参观广东省博物馆
- 初识mina
- C++用new和不用new创建类对象区别
- 项目收获——JSON应用解析
- 烦恼
- Android开发资源整合(SDK、ADT、supports、Platforms、System Images)
- ext2文件系统源代码之acl.c
- 「学习笔记」3.13代码学习
- 如何在notepad++中调用MinGW编译运行程序
- 手把手教你一键U盘装系统