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

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

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

SessionPool:连接池。

SendHandler:处理类。

CharsetEncoder:编码;

CharsetDecoder:解码:

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

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; /**
* 初始化连接
* @author yuanfubiao
*
*/
public class PoolListener implements ServletContextListener { @Override
public void contextDestroyed(ServletContextEvent sce) { } @Override
public void contextInitialized(ServletContextEvent sce) {
String nds_ip = sce.getServletContext().getInitParameter("nds_ip");
String nds_ports = sce.getServletContext().getInitParameter("nds_ports");
SessionPool pool = new SessionPool();
try { pool.init(nds_ip, nds_ports);
} catch (Exception e) {
e.printStackTrace();
}
}
}

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

    <display-name>Apache-Axis2</display-name>
<context-param>
<param-name>nds_ip</param-name>
<param-value>XX.XXX.XXX.XXX</param-value>
</context-param>
<context-param>
<param-name>nds_ports</param-name>
<param-value>12210,12211,12212,12213,12214,12215</param-value>
</context-param>
<listener>
<listener-class>cn.net.easyway.nds.PoolListener</listener-class>
</listener>

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

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.transport.socket.nio.NioSocketConnector; public class SessionPool { private static Log logger = LogFactory.getLog(SessionPool.class);
private static int connNum = 0;
private static String ip = null;
private static Map<String,Integer> connNumPorts = new HashMap<String, Integer>();
private static ConcurrentHashMap<String, IoSession> pool = new ConcurrentHashMap<String, IoSession>(); /**
* 初始化:读取配置文件。创建长连接
* @throws Exception
*/
public void init(String nds_ip,String nds_ports) throws Exception{ String[] ports = nds_ports.split(",");
ip = nds_ip; for(int i=0;i<ports.length;i++){ int port = Integer.parseInt(ports[i]);
ConnectFuture future = null; for(int j=0;j<3;j++){
String connNum = this.getConnNums();
logger.info("创建连接号---->>>>>" + connNum);
connNumPorts.put(connNum, port);
future = SessionPool.createConnect(ip, port);
if(future.isConnected()){
logger.info("创建连接------->" + future.getSession());
pool.put(connNum, future.getSession());
}else{
logger.error("连接创建错误,请检查IP和端口配置!" + future);
}
}
}
} /**
* 获取一个连接
* @param num
* @return
*/
public static IoSession getSession(String strNum){ logger.info("IP端口号:" + ip + "连接序列号:" + strNum + "端口号:" + connNumPorts.get(strNum)); IoSession session = pool.get(strNum); if(null == session || !session.isClosing()){
ConnectFuture newConn = createConnect(ip, connNumPorts.get(strNum)); if(!newConn.isConnected()){
newConn = createConnect(ip,connNumPorts.get(strNum));
}
session = newConn.getSession();
pool.replace(strNum, session);
} return session;
} /**
* 创建连接
* @param ip
* @param port
* @return
*/
private static ConnectFuture createConnect(String strIp,int intPort){ IoConnector connector = new NioSocketConnector(); connector.getFilterChain().addLast("codec"
,new ProtocolCodecFilter(new CharsetCodecFactory())); connector.setHandler(new SendHandler()); ConnectFuture future = connector.connect(new InetSocketAddress(strIp,intPort));
connector.getSessionConfig().setReadBufferSize(128);
future.awaitUninterruptibly(); return future;
} /**
* 生成连接序列号
* @return
*/
private synchronized String getConnNums(){ if(18 == connNum){
connNum = 0;
} connNum++; return String.format("%02x", connNum);
}
}

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

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

import nds.framework.security.NDSMD5;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession; import cm.custom.service.reception.RecResponse;
import cm.custom.service.reception.ReceptionResponseServiceStub; /**
* 业务处理
* @author yuanfubiao
*
*/
public class SendHandler extends IoHandlerAdapter { private static Log logger = LogFactory.getLog(SendHandler.class); @Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
logger.error("连接出错", cause);
} @Override
/**
* 设置空暇时间
*/
public void sessionCreated(IoSession session) throws Exception {
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60);
} /**
* 接受到消息后,通过WS发送给用户管理系统
*/
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String result = message.toString().trim();
String temp = result.substring(0, result.length()-16).trim();
logger.info("接受到的数据:" + result);
//验证签名
String signature = null;
String securityKey = "12345678";
try {
byte binSignature[] = NDSMD5.signPacket(temp.getBytes(), securityKey);
signature = new String(Hex.encodeHex(binSignature));
} catch (Exception e) {
e.printStackTrace();
} String packet = temp + signature.toUpperCase().trim(); if(!result.equalsIgnoreCase(packet)){
logger.error("数字签名不对。错误指令:" + result);
return;
}
logger.info("接受到的数据:" + packet);
RecResponse res = new RecResponse();
res.setResponse(temp);
ReceptionResponseServiceStub stub = new ReceptionResponseServiceStub();
stub.recResponse(res);
} /**
* 连接空暇时。发送心跳包
*/
@Override
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
if(status == IdleStatus.BOTH_IDLE){
session.write("heartbeat");
}
}
}

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

编码

import java.nio.charset.Charset;

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; /**
* 编码
* @author yuanfubiao
*
*/
public class CharsetEncoder extends ProtocolEncoderAdapter{ private final static Charset charset = Charset.forName("utf-8"); @Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
throws Exception { IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);
buff.putString(message.toString(), charset.newEncoder()); buff.flip();
out.write(buff);
}
}

解码

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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; /**
* 解码
* @author yuanfubiao
*
*/
public class CharsetDecoder extends CumulativeProtocolDecoder{
private static Log logger = LogFactory.getLog(CharsetDecoder.class);
@Override
protected boolean doDecode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception { if(in.remaining() >= 9){ //心跳为最小传输长度 byte[] headBytes = new byte[in.limit()];
logger.info("接收到消息" + headBytes.toString());
in.get(headBytes, 0, 9);
String head = new String(headBytes).trim();
if("heartbeat".equalsIgnoreCase(head)){
return true;
} int lenPack = Integer.parseInt(head.substring(5, 9), 16)-9; if(in.remaining() == lenPack){ //验证消息长度
byte[] bodyBytes = new byte[in.limit()];
in.get(bodyBytes,0,lenPack);
String body = new String(bodyBytes);
out.write(head.trim()+body.trim());
return true;
}
in.flip();
return false;
}
return false;
}
}

源代码下载: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. java反射机制 struts2 获取 action、method、invocation、proxy

    ActionInvocation invocation = ActionContext.getContext().getActionInvocation(); Object action = invo ...

  2. Wcf资料收集

    1.简介 http://www.tuicool.com/articles/mqYB32 使用规范 http://blog.51cto.com/zt/219 2.教程系列 http://www.cnbl ...

  3. W3C小组宣布:HTML5标准制定完成

    近日,W3C小组宣布已经完成对HTML5标准以及Canvas 2D性能草案的制定,这就意味着开发人员将会有一个稳定的“计划和实施”目标. Web性能工作组已经推出W3C的两个版本建议草案. Navig ...

  4. PHP SimpleXML

    安装 SimpleXML 扩展需要 PHP 5 支持. 自 PHP 5 起,SimpleXML 函数是 PHP 核心的组成部分.无需安装即可使用这些函数. PHP 5 SimpleXML 函数 函数 ...

  5. 查看sqlserver默认的编码格式

    SQL语句:SELECT COLLATIONPROPERTY('Chinese_PRC_Stroke_CI_AI_KS_WS', 'CodePage') 936 简体中文GBK 950 繁体中文BIG ...

  6. C++ 性能剖析 (二):值语义 (value semantics)

    Value Semantics (值语义) 是C++的一个有趣的话题. 什么是值语义? 简单的说,所有的原始变量(primitive variables)都具有value semantics. 也可以 ...

  7. SQL 把数据从一张表更新到另一张表

    代码写多了,有些使用过的方法和技巧会一时半会想不起来,平日记录下来,方便自己和有需要的人日后查阅. UPDATE tb1 SET tb1.fieldOne = tb2.fieldOne /* 将原始表 ...

  8. C#操作Excel文件(转)

    摘要:本文介绍了Excel对象.C#中的受管代码和非受管代码,并介绍了COM组件在.net环境中的使用. 关键词:受管代码:非受管代码:Excel对象:动态连接库 引言 Excel是微软公司办公自动化 ...

  9. HttpHelper工具类

    /// <summary> /// 类说明:HttpHelper类,用来实现Http访问,Post或者Get方式的,直接访问,带Cookie的,带证书的等方式,可以设置代理 /// 重要提 ...

  10. java-Mysql-SQLServer数据类型匹配速查表

    java-Mysql-SQLServer数据类型匹配速查表 Mysql ************************************ 当前列 ClassName ColumnType Di ...