Mina入门实例
继续上一篇,这篇主要讲通过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入门实例的更多相关文章
- Apache Mina入门实例
一.mina是啥 ApacheMINA是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可扩展性的网络应用程序.它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的 ...
- Apache Mina 入门实例
这个教程是介绍使用Mina搭建基础示例.这个教程内容是以创建一个时间服务器. 以下是这个教程需要准备的东西: MINA 2.0.7 Core JDK 1.5 或更高 SLF4J 1.3.0 或更高 L ...
- Mina入门实例(一)
mina现在用的很多了,之前也有用到,但是毕竟不熟悉,于是查了一些资料,做了一些总结.看代码是最直观的,比什么长篇大论都要好.不过其中重要的理论,也要理解下. 首先是环境,程序运行需要几个包,这里用m ...
- JAVA通信系列二:mina入门总结
一.学习资料 Mina入门实例(一) http://www.cnblogs.com/juepei/p/3939119.html Mina入门教程(二)----Spring4 集成Mina http:/ ...
- React 入门实例教程(转载)
本人转载自: React 入门实例教程
- struts入门实例
入门实例 1 .下载struts-2.3.16.3-all .不摆了.看哈就会下载了. 2 . 解压 后 找到 apps 文件夹. 3. 打开后将 struts2-blank.war ...
- Vue.js2.0从入门到放弃---入门实例
最近,vue.js越来越火.在这样的大浪潮下,我也开始进入vue的学习行列中,在网上也搜了很多教程,按着教程来做,也总会出现这样那样的问题(坑啊,由于网上那些教程都是Vue.js 1.x版本的,现在用 ...
- wxPython中文教程入门实例
这篇文章主要为大家分享下python编程中有关wxPython的中文教程,分享一些wxPython入门实例,有需要的朋友参考下 wxPython中文教程入门实例 wx.Window 是一个基类 ...
- Omnet++ 4.0 入门实例教程
http://blog.sina.com.cn/s/blog_8a2bb17d01018npf.html 在网上找到的一个讲解omnet++的实例, 是4.0下面实现的. 我在4.2上试了试,可以用. ...
随机推荐
- eclipse-android-activity_main/fragment_main文件处理
android新建工程后,在res/layout/下有两个文件,之前用studio的时候貌似没有,只有一个文件,然后再测试Activity切换的时候,一直在纠结这个问题,下面是解决方法: 1)将fra ...
- vs连接mysql
1.打开vs2012在aspx中添加一个Grid view 控件,,. 2,选择新建数据源. 3,选择数据库. 4,选择新建连接. 5,更改成mysql连接. 6,这里的Server name 是你自 ...
- (转)xml节点和元素的关系 .
XML节点是什么呢?当我们在处理XML文件的时候必须要明白XML节点的概念,那么从这里的讲述,你将会了解XML节点对于XML文件的意义,希望对你有所帮助. 在我们学习LINQ删除XML节点之前我们先来 ...
- 《CSS网站布局实录》学习笔记(五)
第五章 CSS内容排版 5.1 文字排版 5.1.1 通栏排版 进行网页通栏排版时,只要直接将段落文字放置于p或者其他对象中,再对段落文字应用间距.行距.字号等样式控制,便形成了排版雏形. 5.1.2 ...
- linux下zip命令使用
linux zip命令 zip -r myfile.zip ./*将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. 2.unzipunzip -o ...
- Java直接插入算法
直接插入算法是将N个带排序的元素看做成一个有序表和一个无序表. 每次从无序表中取一个元素和有序表比较,重复N-1次完成排序. 直接上代码: package test; public class Tes ...
- BOM和DOM的联系和区别
BOM中的对象 Window对象: 是整个BOM的核心,所有对象和集合都以某种方式回接到window对象.Window对象表示整个浏览器窗口,但不必表示其中包含的内容. Document对象: 实际上 ...
- access 2007 vba 开发中学到的知识(三)
打开文件或程序 'API函数声明Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellEx ...
- swing——JFrame基本操作
用JFrame(String String1)创建一个窗口 public void setBounds(int a,int b,int width,int height)设置窗口初始化的位置(a,b) ...
- JS之对象数组遍历?
一.js实现遍历对象 <script> ","destroy":"97%"}; var props = ""; for ...