`

使用mina来开发socket程序

    博客分类:
  • mima
阅读更多

mina早于netty,出自同一人之手。个人感觉netty更棒但项目老大要求使用mina,所以就学习一下mina啦。学习的成果总结如下。

 

使用mina开发socket只需要IoAcceptor、IoHandlerAdapter、NioSocketConnector、ProtocolCodecFactory等几个类基本上就可以进行开发了。

 

首先一个Server(简单实例并非完整代码) 负责Mina服务端的启停

 

/**
 * @author shenbaise(shenbaise1001@126.com)
 * @date 2012-2-10
 * TODO Monitor Server2 将Mina交给spring管理,可以通过web界面来管理Mina的起停,参数设置等等
 */
@Controller("monitorServer2")
public class MonitorServer2 {
	
	private static final int PORT = Constant.remote_port; //定义监听端口 
	
	private IoAcceptor acceptor = null;
	
	private InetSocketAddress socketAddres = null;
	
	@Autowired
	MonitorServerHandler monitorServerHandler;
	
	/**
	 * 启动Server
	 * @throws IOException
	 */
	@RequestMapping("start")
	public void init() throws IOException{
		if(null == acceptor)				//如果 上一个Acceptor没有被关闭,则新创建的Acceptor无法被绑定,同时上一个Acceptor将无法再被关闭。
		acceptor = new NioSocketAcceptor();		
		socketAddres = new InetSocketAddress(Constant.remote_address,PORT);
        // Add two filters : a logger and a codec
        acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
        acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
   
        // Attach the business logic to the server
//        acceptor.setHandler( monitorServerHandler );
        acceptor.setHandler(new MonitorServerHandler());
        // Configurate the buffer size and the iddle time
        acceptor.getSessionConfig().setReadBufferSize( 2048 );
        acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 );
        acceptor.getSessionConfig().setUseReadOperation(true); 
        // And bind !
        acceptor.bind(socketAddres);
	}
	/**
	 * 销毁并退出
	 */
	@RequestMapping("stop")
	public void destroy(){
		if (null!=acceptor) {
			acceptor.unbind(socketAddres);
			acceptor.getFilterChain().clear();	// 清空Filter chain,防止下次重新启动时出现重名错误
			acceptor.dispose();					// 可以另写一个类存储IoAccept,通过spring来创建,这样调用dispose后也会重新创建一个新的。或者可以在init方法内部进行创建。
			acceptor = null;
			//		System.exit(0);		将导致容器停止
		}
		
	}
	
    public static void main(String[] args) throws IOException {
    	MonitorServer2 server = new MonitorServer2();
    	server.init();
    	
    	try {
			Thread.sleep(600000);
			
			server.destroy();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
	
}
 

一个对应的Handler,负责业务逻辑处理

 

@Service("monitorServerHandler")
public class MonitorServerHandler extends IoHandlerAdapter {
	
	@SuppressWarnings("unused")
	@Autowired
	private MCacheClient cache;
	
	private int count = 0;
	
	public static final String ALERT_MSG_CACHE_KEY = "1457261687388459164";
	
	@Override
	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		cause.printStackTrace();
		super.exceptionCaught(session, cause);
	}
	
	/**
	 * 将接收到的消息存库或者缓存
	 */
	
	@Override
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		/*服务端的逻辑一般都在这里写*/

	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
		System.out.println("SERVER=>messageSent:" + (String)message);
		super.messageSent(session, message);
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		System.out.println("SERVER=>sessionClosed: current sessionId:"+session.getId());
		super.sessionClosed(session);
	}

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		System.out.println("SERVER=>sessionCreated: current sessionId:"+session.getId());
		super.sessionCreated(session);
	}

	@Override
	public void sessionIdle(IoSession session, IdleStatus status)
			throws Exception {
		System.out.println("SERVER=>sessionIdle:" + session.getIdleCount( status ));
		super.sessionIdle(session, status);
	}

	@Override
	public void sessionOpened(IoSession session) throws Exception {
		System.out.println("SERVER=>sessionOpened: current sessionId:"+session.getId());
		super.sessionOpened(session);
	}
	
}
 

对应Client端也是类似的,一个类负责连接Server,一个来负责业务逻辑的处理。

 

Client端:

 

public class MonitorClient {
	
	private static final int PORT = 10000;
	public  static String address = "127.0.0.1";
	private static InetSocketAddress socketAddres = new InetSocketAddress(address,PORT);
	
	private NioSocketConnector connector = null; 
	
	/**
	 * 启动(在listener中启动是需要新建一个线程来连接Server,否则web容器会阻塞而无法启动。)
	 */
	public void init(){
		connector = new NioSocketConnector();
		connector.getFilterChain().addLast( "logger", new LoggingFilter() ); 
		connector.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new MyCodeFactory( Charset.forName( "UTF-8" )))); //设置编码过滤器 
		connector.setConnectTimeoutMillis(3000); 
		connector.setHandler(new MonitorClientHandler());//设置事件处理器 
		ConnectFuture cf = connector.connect(socketAddres);//建立连接 
		
		cf.awaitUninterruptibly();

		cf.getSession().getCloseFuture().awaitUninterruptibly();//等待连接断开 
		
	}
	
	/**
	 * 销毁
	 */
	public void destroy(){
		socketAddres = null;
		connector.dispose();
	}
	
	
	public static void main(String[] args) { 
//		MonitorClient client = new MonitorClient();
//		client.init();
//		try {
//			Thread.sleep(70000);
//			
//			client.destroy();
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
		
		ClientThread thread = new ClientThread();
		Thread cThread = new Thread(thread);
		cThread.start();
	}
	/**
	 * 启动(在新建线程中连接Server)
	 */
	public void init2(){
		ClientThread thread = new ClientThread();
		Thread cThread = new Thread(thread);
		cThread.start();
	}
	
}

 Client端的Handler:

 

public class MonitorClientHandler extends IoHandlerAdapter {
	
	int count = 0;
	StringBuilder sb = new StringBuilder();
	int pos = 0;
//	@Autowired BaseDao baseDao;
	
	@Override
	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		cause.printStackTrace();
		super.exceptionCaught(session, cause);
	}

	@Override
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		/*Client端的逻辑会在这里*/
		super.messageReceived(session, message);
	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
                 /*或者会在这里,当然每个地方都会有一些东西需要处理,例如创建、关闭、空闲等等*/
		super.messageSent(session, message);
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		/*这里可以实现重连,但是这会涉及到你代码的一些资源分配或调度逻辑,跑一个线程进行重连*/
		super.sessionClosed(session);
	}

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		System.out.println("CLIENT=>sessionCreated: current sessionId:"+session.getId());
		super.sessionCreated(session);
	}

	@Override
	public void sessionIdle(IoSession session, IdleStatus status)
			throws Exception {
         
		System.out.println("CLIENT=>sessionIdle:" + session.getIdleCount( status ));
		super.sessionIdle(session, status);
	}

	@Override
	public void sessionOpened(IoSession session) throws Exception {
		System.out.println("CLIENT=>sessionOpened: current sessionId:"+session.getId());
		super.sessionOpened(session);
	}
	
}

 最后还有ProtocolCodecFactory也是比较重要的

一个很简单的实现如下:

 

public  class MyCodeFactory implements ProtocolCodecFactory {
		
		private LineDelimiter enLineDelimiter = new LineDelimiter(Constant.CHAR2);
	
	    private final TextLineEncoder encoder;
	    private final TextLineDecoder decoder;
	    /*final static char endchar = 0x1a;*/
	    final static String endchar = Constant.CHAR2;
	    
	    public MyCodeFactory() {
	        this(Charset.forName("gb2312"));
	    }
	    
	    public MyCodeFactory(Charset charset) {
	    	 encoder = new TextLineEncoder(charset, enLineDelimiter);
	         decoder = new TextLineDecoder(charset, enLineDelimiter);
	         
	         }

		public ProtocolDecoder getDecoder(IoSession session) throws Exception {
			// TODO Auto-generated method stub
			return decoder;
		}
		public ProtocolEncoder getEncoder(IoSession session) throws Exception {
			// TODO Auto-generated method stub
			return encoder;
		}
		public int getEncoderMaxLineLength() {
	        return encoder.getMaxLineLength();
	    }
	    public void setEncoderMaxLineLength(int maxLineLength) {
	        encoder.setMaxLineLength(maxLineLength);
	    }
	    public int getDecoderMaxLineLength() {
	        return decoder.getMaxLineLength();
	    }
	    public void setDecoderMaxLineLength(int maxLineLength) {
	        decoder.setMaxLineLength(maxLineLength);
	    }

}

 mina的TextLineCodecFactory默认以换行来进行分隔,我们也可以自定义。以TextLineCodecFactory为例,mina在发送是会在发送内容之后自动加一个换行符,在接收时会按换行符来截取收到的内容。

 

在web工程中启动mina客户端时应该新开一个线程,不要用主线程。

分享到:
评论
2 楼 hrs07 2014-02-07  
    楼主,您好。我也在学习MINA。不过,我在使用MINA编写客户端/服务器端应用的时候碰到了一个奇怪的问题。
    我的服务器端在接收到客户端发来的request之后,在messageReceived(IoSession session, Object message)里调用session.write(response)发送response成功之后,会自动关闭当前的session。这是怎么回事?请问您有碰到过类似问题吗?
1 楼 烽火抢票 2013-12-02  
     

相关推荐

    Android-MinaSocket一款基于Mina的Socket长连接库

    6. **封装与易用性**:`Android-MinaSocket` 对Mina进行了封装,为Android开发者提供更友好的API,降低了使用门槛。 在实际使用`Android-MinaSocket` 时,开发者需要注意以下几点: - **连接管理**:保持长连接...

    mina框架中socket使用,有服务端和客户端。

    mina框架是Apache组织开发的一个网络通信框架,...通过这个项目,开发者不仅可以学习到MINA框架的基础使用,还能了解网络编程中的服务端与客户端交互原理,以及如何利用MINA提供的工具来构建高效、稳定的网络应用程序。

    Mina Socket 源代码

    通过分析 Mina Socket 的源代码,我们可以理解其如何高效地处理网络通信,并为开发人员提供了一个灵活的平台,以构建复杂、高性能的网络应用。理解并掌握这些关键概念,有助于你更有效地利用 Mina 框架实现自己的...

    Socket及Mina的讲解

    总结来说,Socket和Apache Mina在AndroidPN项目中的应用主要体现在以下几个方面: 1. 提供稳定的网络连接:Socket为基础的连接机制,Mina则通过异步I/O和事件驱动模式优化了连接管理。 2. 数据传输:两者都能支持...

    mina2 实例程序(socket通讯调用远程方法)

    本篇文章将深入探讨如何使用Mina2进行Socket通信,并实现远程方法调用。 Apache Mina2是一个基于事件驱动和异步模型的网络应用框架,它为各种协议如TCP/IP、UDP/IP和HTTP等提供了一种统一的抽象层。Mina2通过高度...

    socket通信,mina长连接通信

    在实际开发中,你可以根据项目需求选择适合的技术栈,例如使用MINA来构建稳定的长连接服务,配合Socket短连接用于一次性通信任务。提供的压缩包文件"SOCKET通信"可能包含了使用Socket和MINA的示例代码和库文件,可以...

    socket 与 mina 交互数据

    Mina(Apache MINA)是一个高度可扩展的网络应用程序开发框架,它为开发者提供了异步API,可以处理大量的并发连接。Mina的核心思想是事件驱动和非阻塞I/O,这使得它在处理高并发场景时性能优越。在Mina中,我们创建...

    socket mina测试框架

    Socket Mina测试框架是一个强大的网络通信应用框架,主要用于简化Java应用程序与远程服务器之间的通信。它提供了高度可扩展和高性能的I/O处理模型,使得开发者能够更专注于业务逻辑,而不是底层的网络实现细节。Mina...

    mina框架中socket应用的简单小项目,包含了所需jar

    "mina框架中socket应用的简单小项目,包含了所需jar" 这个标题告诉我们这是一个关于使用Apache MINA框架实现的基于Socket通信的小型项目。MINA是一个为高性能网络应用提供高度抽象的Java NIO框架,它简化了网络编程...

    java客户端socket与mina服务端通信

    Mina(Minimum Asynchronous Network)是一个高性能、易于使用的网络应用框架,它简化了开发复杂、高性能的网络应用程序的过程。Mina提供了一种事件驱动、非阻塞I/O的模型,这使得它在处理大量并发连接时性能优异。...

    apache mina socket

    在本文中,我们将深入探讨Apache Mina的核心概念、设计模式以及如何使用它来实现基于Socket的通信。 **Apache Mina的核心概念:** 1. **Event-Driven模型**:Mina采用了事件驱动模型,当网络事件(如数据接收、...

    MINA2 教程 socket

    在这个"MINA2 教程 socket"中,我们将探讨如何使用MINA2来实现服务器与客户端之间的通信,并且支持同时在线连接,以及如何利用`newFixedThreadPool`线程池来优化处理并发连接。 1. **MINA2基本概念**: MINA2的...

    MinaDemo.zip SpringBoot集成Socket通讯

    在IT行业中,网络通信是应用程序之间交互的重要方式,而Socket通信是实现这一目标的基础。SpringBoot作为现代化的Java开发框架,极大地简化了Spring的应用启动和配置。MyBatis则是一个优秀的持久层框架,用于简化...

    socket通讯和mina应用

    Socket通讯和MINA应用是Java网络编程中的两个关键概念,它们在开发分布式系统、网络服务和客户端应用程序中扮演着重要角色。这篇博文将深入探讨这两个主题,并通过一个名为"testMina"的压缩包文件来展示实际应用。 ...

    HPsocket 封包与mina对接

    本文将重点介绍如何使用HPsocket的`TcpPackServer`类来实现封包功能,并与Apache Mina框架进行对接。 #### 二、HPsocket封包规则解析 在HPsocket中,`TcpPackServer`提供了对封包的支持,其封包模型包头格式为: `...

    基于Android开发MINA框架使用详解

    此时,我们可以借助开源框架MINA(Multi-purpose Infrastructure for Network Applications)来构建高效、可扩展的网络应用程序。MINA是一个用Java编写的高性能、异步I/O框架,适用于多种传输协议,如TCP/IP和UDP/IP...

    mina 包 socket 框架

    在本文中,我们将深入探讨Mina包如何作为Socket框架来使用,以及它在实际开发中的优势。 首先,Mina的核心是它的事件驱动模型,这允许它在多线程环境中高效处理并发连接。通过使用I/O多路复用技术如Java的Selector...

    网络编程(socket、NIO、mina)---demo

    总结来说,这个"网络编程(socket、NIO、mina)---demo"涵盖了网络编程的基础与进阶,从基础的Socket通信,到提高性能的NIO,再到高级的Mina框架,这些都是开发分布式系统、网络服务和实时通信应用不可或缺的技术。...

    apache mina-spring 服务端程序

    Spring框架则是一个广泛使用的Java企业级应用开发框架,它简化了依赖注入、AOP(面向切面编程)以及数据访问等任务。 在这个"apache mina-spring 服务端程序"项目中,Mina和Spring被整合在一起,创建了一个高效的...

    Java springboot 整合mina 框架,nio通讯基础教程,mina框架基础教程.zip

    总结来说,本教程将引导你从理论到实践,掌握Java NIO的基本原理,理解Mina框架的使用,以及如何在SpringBoot环境中整合Mina实现高效的网络通信。通过这些知识的学习,你将具备开发高并发、高性能网络应用的能力。

Global site tag (gtag.js) - Google Analytics