继续上一篇,这篇主要讲通过mina往B端发送消息。并接受消息,mina是一个网络通信框架,封装了javaNIO。简单易用。网上有非常多关于他的介绍,在此不赘述了。

如上篇所介绍,完毕功能,须要五个类:

PoolListener:监听,用来在系统启动的时候创建连接。

SessionPool:连接池。

SendHandler:处理类。

CharsetEncoder:编码;

CharsetDecoder:解码:

B为我们提供了6个port。每一个port可建立3个长连接。因此。在系统时,就要创建长连接,以下是一个监听类:

  1. import javax.servlet.ServletContextEvent;
  2. import javax.servlet.ServletContextListener;
  3.  
  4. /**
  5. * 初始化连接
  6. * @author yuanfubiao
  7. *
  8. */
  9. public class PoolListener implements ServletContextListener {
  10.  
  11. @Override
  12. public void contextDestroyed(ServletContextEvent sce) {
  13.  
  14. }
  15.  
  16. @Override
  17. public void contextInitialized(ServletContextEvent sce) {
  18. String nds_ip = sce.getServletContext().getInitParameter("nds_ip");
  19. String nds_ports = sce.getServletContext().getInitParameter("nds_ports");
  20. SessionPool pool = new SessionPool();
  21. try {
  22.  
  23. pool.init(nds_ip, nds_ports);
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }

以下是监听配置,是配置在web.xml中:

  1. <display-name>Apache-Axis2</display-name>
  2. <context-param>
  3. <param-name>nds_ip</param-name>
  4. <param-value>XX.XXX.XXX.XXX</param-value>
  5. </context-param>
  6. <context-param>
  7. <param-name>nds_ports</param-name>
  8. <param-value>12210,12211,12212,12213,12214,12215</param-value>
  9. </context-param>
  10. <listener>
  11. <listener-class>cn.net.easyway.nds.PoolListener</listener-class>
  12. </listener>

以下是自己维护的一个连接池,相同使用并发包中的ConcurrentHashMap实现,他也是线程安全的,代码例如以下:

  1. import java.net.InetSocketAddress;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import java.util.concurrent.ConcurrentHashMap;
  5.  
  6. import org.apache.commons.logging.Log;
  7. import org.apache.commons.logging.LogFactory;
  8. import org.apache.mina.core.future.ConnectFuture;
  9. import org.apache.mina.core.service.IoConnector;
  10. import org.apache.mina.core.session.IoSession;
  11. import org.apache.mina.filter.codec.ProtocolCodecFilter;
  12. import org.apache.mina.transport.socket.nio.NioSocketConnector;
  13.  
  14. public class SessionPool {
  15.  
  16. private static Log logger = LogFactory.getLog(SessionPool.class);
  17. private static int connNum = 0;
  18. private static String ip = null;
  19. private static Map<String,Integer> connNumPorts = new HashMap<String, Integer>();
  20. private static ConcurrentHashMap<String, IoSession> pool = new ConcurrentHashMap<String, IoSession>();
  21.  
  22. /**
  23. * 初始化:读取配置文件。创建长连接
  24. * @throws Exception
  25. */
  26. public void init(String nds_ip,String nds_ports) throws Exception{
  27.  
  28. String[] ports = nds_ports.split(",");
  29. ip = nds_ip;
  30.  
  31. for(int i=0;i<ports.length;i++){
  32.  
  33. int port = Integer.parseInt(ports[i]);
  34. ConnectFuture future = null;
  35.  
  36. for(int j=0;j<3;j++){
  37. String connNum = this.getConnNums();
  38. logger.info("创建连接号---->>>>>" + connNum);
  39. connNumPorts.put(connNum, port);
  40. future = SessionPool.createConnect(ip, port);
  41. if(future.isConnected()){
  42. logger.info("创建连接------->" + future.getSession());
  43. pool.put(connNum, future.getSession());
  44. }else{
  45. logger.error("连接创建错误,请检查IP和端口配置!" + future);
  46. }
  47. }
  48. }
  49. }
  50.  
  51. /**
  52. * 获取一个连接
  53. * @param num
  54. * @return
  55. */
  56. public static IoSession getSession(String strNum){
  57.  
  58. logger.info("IP端口号:" + ip + "连接序列号:" + strNum + "端口号:" + connNumPorts.get(strNum));
  59.  
  60. IoSession session = pool.get(strNum);
  61.  
  62. if(null == session || !session.isClosing()){
  63. ConnectFuture newConn = createConnect(ip, connNumPorts.get(strNum));
  64.  
  65. if(!newConn.isConnected()){
  66. newConn = createConnect(ip,connNumPorts.get(strNum));
  67. }
  68. session = newConn.getSession();
  69. pool.replace(strNum, session);
  70. }
  71.  
  72. return session;
  73. }
  74.  
  75. /**
  76. * 创建连接
  77. * @param ip
  78. * @param port
  79. * @return
  80. */
  81. private static ConnectFuture createConnect(String strIp,int intPort){
  82.  
  83. IoConnector connector = new NioSocketConnector();
  84.  
  85. connector.getFilterChain().addLast("codec"
  86. ,new ProtocolCodecFilter(new CharsetCodecFactory()));
  87.  
  88. connector.setHandler(new SendHandler());
  89.  
  90. ConnectFuture future = connector.connect(new InetSocketAddress(strIp,intPort));
  91. connector.getSessionConfig().setReadBufferSize(128);
  92. future.awaitUninterruptibly();
  93.  
  94. return future;
  95. }
  96.  
  97. /**
  98. * 生成连接序列号
  99. * @return
  100. */
  101. private synchronized String getConnNums(){
  102.  
  103. if(18 == connNum){
  104. connNum = 0;
  105. }
  106.  
  107. connNum++;
  108.  
  109. return String.format("%02x", connNum);
  110. }
  111. }

因此。在项目启动的时候就会有18个连接自己主动创建。并放在pool中等待我们的使用。

以下是业务处理类。须要继承IoHandlerAdapter类。而且实现以下几个方法:

  1. import nds.framework.security.NDSMD5;
  2.  
  3. import org.apache.commons.codec.binary.Hex;
  4. import org.apache.commons.logging.Log;
  5. import org.apache.commons.logging.LogFactory;
  6. import org.apache.mina.core.service.IoHandlerAdapter;
  7. import org.apache.mina.core.session.IdleStatus;
  8. import org.apache.mina.core.session.IoSession;
  9.  
  10. import cm.custom.service.reception.RecResponse;
  11. import cm.custom.service.reception.ReceptionResponseServiceStub;
  12.  
  13. /**
  14. * 业务处理
  15. * @author yuanfubiao
  16. *
  17. */
  18. public class SendHandler extends IoHandlerAdapter {
  19.  
  20. private static Log logger = LogFactory.getLog(SendHandler.class);
  21.  
  22. @Override
  23. public void exceptionCaught(IoSession session, Throwable cause)
  24. throws Exception {
  25. logger.error("连接出错", cause);
  26. }
  27.  
  28. @Override
  29. /**
  30. * 设置空暇时间
  31. */
  32. public void sessionCreated(IoSession session) throws Exception {
  33. session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60);
  34. }
  35.  
  36. /**
  37. * 接受到消息后,通过WS发送给用户管理系统
  38. */
  39. @Override
  40. public void messageReceived(IoSession session, Object message)
  41. throws Exception {
  42. String result = message.toString().trim();
  43. String temp = result.substring(0, result.length()-16).trim();
  44. logger.info("接受到的数据:" + result);
  45. //验证签名
  46. String signature = null;
  47. String securityKey = "12345678";
  48. try {
  49. byte binSignature[] = NDSMD5.signPacket(temp.getBytes(), securityKey);
  50. signature = new String(Hex.encodeHex(binSignature));
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. }
  54.  
  55. String packet = temp + signature.toUpperCase().trim();
  56.  
  57. if(!result.equalsIgnoreCase(packet)){
  58. logger.error("数字签名不对。错误指令:" + result);
  59. return;
  60. }
  61. logger.info("接受到的数据:" + packet);
  62. RecResponse res = new RecResponse();
  63. res.setResponse(temp);
  64. ReceptionResponseServiceStub stub = new ReceptionResponseServiceStub();
  65. stub.recResponse(res);
  66. }
  67.  
  68. /**
  69. * 连接空暇时。发送心跳包
  70. */
  71. @Override
  72. public void sessionIdle(IoSession session, IdleStatus status)
  73. throws Exception {
  74. if(status == IdleStatus.BOTH_IDLE){
  75. session.write("heartbeat");
  76. }
  77. }
  78. }

一般我们在写socket程序时。用堵塞的方式读取消息,通常是依据消息换行符或者特殊字符,或者对方关闭流来证明一条信息读取完毕,在mina中,有默认的编解码方式。但也能够自己定义,比方以长度来推断一条消息是否读取完毕:

编码

  1. import java.nio.charset.Charset;
  2.  
  3. import org.apache.mina.core.buffer.IoBuffer;
  4. import org.apache.mina.core.session.IoSession;
  5. import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
  6. import org.apache.mina.filter.codec.ProtocolEncoderOutput;
  7.  
  8. /**
  9. * 编码
  10. * @author yuanfubiao
  11. *
  12. */
  13. public class CharsetEncoder extends ProtocolEncoderAdapter{
  14.  
  15. private final static Charset charset = Charset.forName("utf-8");
  16.  
  17. @Override
  18. public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
  19. throws Exception {
  20.  
  21. IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);
  22. buff.putString(message.toString(), charset.newEncoder());
  23.  
  24. buff.flip();
  25. out.write(buff);
  26. }
  27. }

解码

  1. import org.apache.commons.logging.Log;
  2. import org.apache.commons.logging.LogFactory;
  3. import org.apache.mina.core.buffer.IoBuffer;
  4. import org.apache.mina.core.session.IoSession;
  5. import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
  6. import org.apache.mina.filter.codec.ProtocolDecoderOutput;
  7.  
  8. /**
  9. * 解码
  10. * @author yuanfubiao
  11. *
  12. */
  13. public class CharsetDecoder extends CumulativeProtocolDecoder{
  14. private static Log logger = LogFactory.getLog(CharsetDecoder.class);
  15. @Override
  16. protected boolean doDecode(IoSession session, IoBuffer in,
  17. ProtocolDecoderOutput out) throws Exception {
  18.  
  19. if(in.remaining() >= 9){ //心跳为最小传输长度
  20.  
  21. byte[] headBytes = new byte[in.limit()];
  22. logger.info("接收到消息" + headBytes.toString());
  23. in.get(headBytes, 0, 9);
  24. String head = new String(headBytes).trim();
  25. if("heartbeat".equalsIgnoreCase(head)){
  26. return true;
  27. }
  28.  
  29. int lenPack = Integer.parseInt(head.substring(5, 9), 16)-9;
  30.  
  31. if(in.remaining() == lenPack){ //验证消息长度
  32. byte[] bodyBytes = new byte[in.limit()];
  33. in.get(bodyBytes,0,lenPack);
  34. String body = new String(bodyBytes);
  35. out.write(head.trim()+body.trim());
  36. return true;
  37. }
  38. in.flip();
  39. return false;
  40. }
  41. return false;
  42. }
  43. }

源代码下载:http://download.csdn.net/detail/stubbornpotatoes/7438435

关于mina发现一个系列好文章:http://xxgblog.com/2014/10/16/mina-netty-twisted-10/

Mina入门实例的更多相关文章

  1. Apache Mina入门实例

    一.mina是啥 ApacheMINA是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可扩展性的网络应用程序.它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的 ...

  2. Apache Mina 入门实例

    这个教程是介绍使用Mina搭建基础示例.这个教程内容是以创建一个时间服务器. 以下是这个教程需要准备的东西: MINA 2.0.7 Core JDK 1.5 或更高 SLF4J 1.3.0 或更高 L ...

  3. Mina入门实例(一)

    mina现在用的很多了,之前也有用到,但是毕竟不熟悉,于是查了一些资料,做了一些总结.看代码是最直观的,比什么长篇大论都要好.不过其中重要的理论,也要理解下. 首先是环境,程序运行需要几个包,这里用m ...

  4. JAVA通信系列二:mina入门总结

    一.学习资料 Mina入门实例(一) http://www.cnblogs.com/juepei/p/3939119.html Mina入门教程(二)----Spring4 集成Mina http:/ ...

  5. React 入门实例教程(转载)

    本人转载自: React 入门实例教程

  6. struts入门实例

    入门实例 1  .下载struts-2.3.16.3-all  .不摆了.看哈就会下载了. 2  . 解压  后 找到 apps 文件夹. 3.    打开后将 struts2-blank.war   ...

  7. Vue.js2.0从入门到放弃---入门实例

    最近,vue.js越来越火.在这样的大浪潮下,我也开始进入vue的学习行列中,在网上也搜了很多教程,按着教程来做,也总会出现这样那样的问题(坑啊,由于网上那些教程都是Vue.js 1.x版本的,现在用 ...

  8. wxPython中文教程入门实例

    这篇文章主要为大家分享下python编程中有关wxPython的中文教程,分享一些wxPython入门实例,有需要的朋友参考下     wxPython中文教程入门实例 wx.Window 是一个基类 ...

  9. Omnet++ 4.0 入门实例教程

    http://blog.sina.com.cn/s/blog_8a2bb17d01018npf.html 在网上找到的一个讲解omnet++的实例, 是4.0下面实现的. 我在4.2上试了试,可以用. ...

随机推荐

  1. eclipse-android-activity_main/fragment_main文件处理

    android新建工程后,在res/layout/下有两个文件,之前用studio的时候貌似没有,只有一个文件,然后再测试Activity切换的时候,一直在纠结这个问题,下面是解决方法: 1)将fra ...

  2. vs连接mysql

    1.打开vs2012在aspx中添加一个Grid view 控件,,. 2,选择新建数据源. 3,选择数据库. 4,选择新建连接. 5,更改成mysql连接. 6,这里的Server name 是你自 ...

  3. (转)xml节点和元素的关系 .

    XML节点是什么呢?当我们在处理XML文件的时候必须要明白XML节点的概念,那么从这里的讲述,你将会了解XML节点对于XML文件的意义,希望对你有所帮助. 在我们学习LINQ删除XML节点之前我们先来 ...

  4. 《CSS网站布局实录》学习笔记(五)

    第五章 CSS内容排版 5.1 文字排版 5.1.1 通栏排版 进行网页通栏排版时,只要直接将段落文字放置于p或者其他对象中,再对段落文字应用间距.行距.字号等样式控制,便形成了排版雏形. 5.1.2 ...

  5. linux下zip命令使用

    linux zip命令 zip -r myfile.zip ./*将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. 2.unzipunzip -o ...

  6. Java直接插入算法

    直接插入算法是将N个带排序的元素看做成一个有序表和一个无序表. 每次从无序表中取一个元素和有序表比较,重复N-1次完成排序. 直接上代码: package test; public class Tes ...

  7. BOM和DOM的联系和区别

    BOM中的对象 Window对象: 是整个BOM的核心,所有对象和集合都以某种方式回接到window对象.Window对象表示整个浏览器窗口,但不必表示其中包含的内容. Document对象: 实际上 ...

  8. access 2007 vba 开发中学到的知识(三)

    打开文件或程序 'API函数声明Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellEx ...

  9. swing——JFrame基本操作

    用JFrame(String String1)创建一个窗口 public void setBounds(int a,int b,int width,int height)设置窗口初始化的位置(a,b) ...

  10. JS之对象数组遍历?

    一.js实现遍历对象 <script> ","destroy":"97%"}; var props = ""; for ...