客户端通信过程
1.通过SocketConnector同服务器端建立连接
2.链接建立之后I/O的读写交给了I/O Processor线程,I/O Processor是多线程的
3.通过I/O Processor读取的数据经过IoFilterChain里所有配置的IoFilter,IoFilter进行消息的过滤,格式的转换,在这个层面可以制定一些自定义的协议
4.最后IoFilter将数据交给Handler进行业务处理,完成了整个读取的过程
5.写入过程也是类似,只是刚好倒过来,通过IoSession.write写出数据,然后Handler进行写入的业务处理,处理完成后交给IoFilterChain,进行消息过滤和协议的转换,最后通过I/O Processor将数据写出到socket通道
IoFilterChain作为消息过滤链
1.读取的时候是从低级协议到高级协议的过程,一般来说从byte字节逐渐转换成业务对象的过程
2.写入的时候一般是从业务对象到字节byte的过程
IoSession贯穿整个通信过程的始终
整个过程可以用一个图来表现
消息箭头都是有NioProcessor-N线程发起调用,默认情况下也在NioProcessor-N线程中执行
类图
http://mina.apache.org/class-diagrams.html#ClassDiagrams-ProtocolDecoderclassdiagram
Connector
作为连接客户端,SocketConector用来和服务器端建立连接,连接成功,创建IoProcessor
Thread(不能超过指定的processorCount),Thread由指定的线程池进行管理,IoProcessor
利用NIO框架对IO进行处理,同时创建IoSession。连接的建立是通过Nio的SocketChannel进行。
NioSocketConnector connector = new NioSocketConnector(processorCount);
ConnectFuture future = connector.connect(new InetSocketAddress(HOSTNAME, PORT));建立一个I/O通道
Acceptor
作为服务器端的连接接受者,SocketAcceptor用来监听端口,同客户端建立连接,连接建立之后的I/O操作全部交给IoProcessor进行处理
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.bind( new InetSocketAddress(PORT) );
Protocol
利用IoFilter,对消息进行解码和编码,如以下代码通过 MyProtocolEncoder 将java对象转成byte串,通过MyProtocalDecoder 将byte串恢复成java对象
-
connector.getFilterChain().addLast("codec",
new
ProtocolCodecFilter(
new
MyProtocalFactory()));
-
......
-
public
class
MyProtocalFactory
implements
ProtocolCodecFactory {
-
ProtocolEncoderAdapter encoder = new
MyProtocolEncoder();
-
ProtocolDecoder decoder = new
MyProtocalDecoder() ;
-
public
ProtocolDecoder getDecoder(IoSession session)
throws
Exception {
-
return
decoder;
-
}
-
public
ProtocolEncoder getEncoder(IoSession session)
throws
Exception {
-
return
encoder;
-
}
-
}
-
......
-
public
class
MyProtocalDecoder
extends
ProtocolDecoderAdapter {
-
-
public
void
decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
-
throws
Exception {
-
-
int
id = in.getInt();
-
int
len = in.getInt();
-
byte
[] dst =
new
byte
[len];
-
-
in.get(dst);
-
-
String name = new
String(dst,"GBK");
-
-
Item item = new
Item();
-
item.setId(id);
-
item.setName(name);
-
out.write(item);
-
}
-
}
-
......
-
public
class
MyProtocolEncoder
extends
ProtocolEncoderAdapter {
-
-
public
void
encode(IoSession session, Object message,
-
ProtocolEncoderOutput out) throws
Exception {
-
Item item = (Item)message;
-
int
byteLen =
8
+ item.getName().getBytes("GBK").length ;
-
IoBuffer buf = IoBuffer.allocate(byteLen);
-
buf.putInt(item.getId());
-
buf.putInt(item.getName().getBytes("GBK").length);
-
buf.put(item.getName().getBytes("GBK"));
-
buf.flip();
-
out.write(buf);
-
-
}
-
}
handler
具体处理事件,事件包括:sessionCreated、sessionOpened、sessionClosed、sessionIdle、exceptionCaught、messageReceived、messageSent。
connector.setHandler(new MyHandler());MyHandler继承IoHandlerAdapter类或者实现IoHandler接口.事件最终由IoProcessor线程发动调用。
Processor
I/O处理器、允许多线程读写,开发过程中只需要指定线程数量,Processor通过Nio框架进行I/O的续写操作,Processor包含
了Nio的Selector的引用。这点也正是mina的优势,如果直接用Nio编写,则需要自己编写代码来实现类似Processor的功能。正因为
I/O
Processor是异步处理读写的,所以我们有时候需要识别同一个任务的消息,比如一个任务包括发送消息,接收消息,反馈消息,那么我们需要在制定消息
格式的时候,消息头里能包含一个能识别是同一个任务的id。
I/O Porcessor线程数的设置 :如果是SocketConnector,则可以在构造方法中指定,如:new
SocketConnector(processorCount,
Executors.newCachedThreadPool());如果是SocketAcceptor,也是一样的:SocketAcceptor
acceptor = new SocketAcceptor(ProcessorCount,
Executors.newCachedThreadPool());
processorCount为最大Porcessor线程数,这个值可以通过性能测试进行调优,默认值是cpu核数量+1(Runtime.getRuntime().availableProcessors() + 1)。
比较奇怪的是,每个IoProcessor在创建的时候会本地自己和自己建立一个连接?
IoSession
IoSession是用来保持IoService的上下文,一个IoService在建立Connect之后建立一个IoSession(一个连接一个session),IoSession的生命周期从Connection建立到断开为止
IoSession做两件事情:
1.通过IoSession可以获取IoService的所有相关配置对象(持有对IoService,Processor池,SocketChannel,SessionConfig和IoService.IoHandler的引用)
2.通过IoSession.write 是数据写出的入口
关于线程
http://mina.apache.org/configuring-thread-model.html
ThreadModel 1.x版本的mina还有线程模式选项在2.x之后就没有了
1.x版本指定线程模式
SocketConnectorConfig cfg = new SocketConnectorConfig();
cfg.setThreadModel(ThreadModel.MANUAL);
MINA有3种worker线程
Acceptor、Connector、I/O processor 线程
Acceptor Thread
一般作为服务器端链接的接收线程,实现了接口IoService,线程的数量就是创建SocketAcceptor 的数量
Connector Thread
一般作为客户端的请求建立链接线程,实现了接口IoService,维持了一个和服务器端Acceptor的一个链接,线程数量就是创建SocketConnector 的数量
Mina的SocketAcceptor和SocketConnector均是继承了BaseIoService,是对IoService的两种不同的实现
I/O processor Thread
作为I/O真正处理的线程,存在于服务器端和客户端,用来处理I/O的读写操作,线程的数量是可以配置的,默认最大数量是CPU个数+1
服务器端:在创建SocketAcceptor的时候指定ProcessorCount
SocketAcceptor acceptor = new SocketAcceptor(Runtime.getRuntime().availableProcessors() + 1, Executors.newCachedThreadPool());
客户端:在创建SocketConnector 的时候指定ProcessorCount
SocketConnector connector = new
SocketConnector(Runtime.getRuntime().availableProcessors() + 1,
Executors.newCachedThreadPool());
I/O Processor Thread,是依附于IoService,类似上面的例子SocketConnector connector =
new SocketConnector(Runtime.getRuntime().availableProcessors() + 1,
Executors.newCachedThreadPool());是指SocketConnector这个线程允许CPU+1个I/O
Processor Thread
NioProcessor虽然是多线程,但是对与一个连接的时候业务处理只会使用一个线程进行处理(Processor线程对于一个客户端连接只
使用一个线程NioProcessor-n)如果handler的业务比较耗时,会导致NioProcessor线程堵塞
,在2个客户端同时连接上来的时候会创建第2个(前提是第1个NioProcessor正在忙),创建的最大数量由Acceptor构造方法的时候指定。
如果:一个客户端连接同服务器端有很多通信,并且I/O的开销不大,但是Handler处理的业务时间比较长,那么需要采用独立的线程模式,在
FilterChain的最后增加一个ExecutorFitler
:
acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
这样可以保证processor和handler的线程是分开的,否则:客户端发送3个消息,而服务器对于每个消息要处理10s左右,那么这3个消息是被串行处理,在处理第一个消息的时候,后面的消息将被堵塞,同样反过来客户端也有同样的问题。
客户端Porcessor堵塞测试情况:
1.以下代码在建立连接后连续发送了5个消息(item)
-
ConnectFuture future = connector.connect(
new
InetSocketAddress(HOSTNAME, PORT));
-
future.awaitUninterruptibly();
-
session = future.getSession();
-
Item item = new
Item();
-
item.setId(12345
);
-
item.setName("hi");
-
session.write(item);
-
session.write(item);
-
session.write(item);
-
session.write(item);
-
session.write(item);
2.在handle的messageSent方法进行了延时处理,延时3秒
-
public
void
messageSent(IoSession session, Object message)
throws
Exception {
-
Thread.sleep(3000
);
-
System.out.println(message);
-
-
}
3.测试结果
5个消息是串行发送,都由同一个IoPorcessor线程处理
-
session.write(item);
-
session.write(item);
-
session.write(item);
-
session.write(item);
-
session.write(item);
服务器端每隔3秒收到一个消息。因为调用是由IoProcessor触发,而一个connector只会使用一个IoProcessor线程
4.增加ExecutorFilter,ExecutorFilter保证在处理handler的时候是独立线程
connector.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
5.测试结果
4个session.wirte变成了并行处理,服务器端同时收到了5条消息
分享到:
相关推荐
Apache Mina是一个高性能的网络应用程序框架,它简化了网络编程,使得开发者可以更加容易地创建可伸缩的网络应用程序。Mina支持异步I/O操作,适用于需要大量并发连接的应用,比如聊天服务器、邮件服务器、游戏服务器...
Apache MINA (Multipurpose Infrastructure for Network Applications) 是一个高性能、异步事件驱动的网络应用程序框架,主要用于简化开发网络服务或协议。MINA 提供了一种统一的编程模型,支持多种传输层协议,如...
# Mina框架详解 ## 一、Mina框架概述 Mina框架,全称为Apache Mina Server,是一款基于Java的高效、可扩展性强大的网络通信应用框架。它主要支持TCP/IP与UDP/IP协议栈,同时也提供了序列化服务、虚拟机管道通信等...
Mina基础示例 Mina,全称是Java Mina框架,是一个开源的网络通信应用框架,主要用于构建高性能、高可用性的网络服务器。Mina旨在简化网络编程,它提供了高级抽象,如事件驱动和异步I/O,使得开发者能够专注于业务...
Apache Mina通信原理Apache Mina通信原理
本文将深入探讨mina编解码器的工作原理,提供一个典型编解码器的示例,并解析其代码。 1. **mina框架基础** - Mina提供了一个高效的、事件驱动的网络应用程序框架,简化了网络编程,尤其是TCP和UDP通信。 - 它...
在IT行业中,网络通信是软件开发中的重要组成部分,特别是在分布式系统和实时数据交换的应用中。Mina和Socket是两种常见的网络通信框架和技术,它们在...理解这两者的原理和用法,对于提升Java网络编程技能至关重要。
日常笔记-Mina通信原理
总结来说,本教程将引导你从理论到实践,掌握Java NIO的基本原理,理解Mina框架的使用,以及如何在SpringBoot环境中整合Mina实现高效的网络通信。通过这些知识的学习,你将具备开发高并发、高性能网络应用的能力。
2. **NIO原理**:学习非阻塞I/O的工作方式,以及Mina如何利用NIO提高性能和处理大量并发连接。 3. **Mina API**:熟悉Mina的主要类和接口,如`IoSession`、`IoHandler`、`IoFilter`等,并学会如何在项目中使用它们...
如果是一个源码项目,开发者可以通过阅读和修改代码来学习MinaServer的实现原理,理解如何在Android环境中配置和使用Apache Mina框架。如果是APK文件,用户可以直接安装到兼容的Android设备上运行和测试MinaServer...
这个文件提供了Mina框架的源代码,对开发者深入理解Mina的工作原理和定制化需求非常有帮助。通过阅读源码,开发者可以学习到如何设计和实现一个高性能的网络通信框架,也可以根据项目需求进行扩展和修改,增强Mina...
在这个"apache-mina源码"中,我们可以深入理解MINA的设计原理和实现细节。 MINA的核心概念包括: 1. **IoSession**:IoSession是MINA中的核心组件,代表了服务端和客户端之间的连接。它包含了会话的状态信息,如...
总的来说,解决MINA的断线重连死锁问题需要深入理解MINA框架的工作原理,结合并发编程的最佳实践,通过细心的代码审查和测试,才能有效地避免和解决这类问题。对于开发者来说,不断学习和掌握网络编程以及并发控制的...
这个Demo是学习Mina网络通信开发的绝佳起点,不仅可以帮助你深入理解Mina的工作原理,还能够指导你如何将Mina应用到实际项目中,构建高性能的网络服务。通过阅读和分析源代码,你将能够更熟练地运用Mina进行网络应用...
3. **Mina2源码分析**(Mina2源码分析.doc):源码分析文档通常由经验丰富的开发者编写,通过深入剖析MINA的源代码,揭示其内部工作原理,帮助开发者理解MINA如何实现非阻塞I/O,以及如何高效地处理网络连接和数据...
在“apache-mina-2.0.3”这个压缩包中,包含了MINA框架的源代码,开发者可以通过阅读源码来深入理解MINA的工作原理,定制自己的网络应用,或者参与MINA的二次开发。这个版本的MINA经过了广泛的测试和优化,稳定性和...
- 揭示了Mina框架内部的工作原理,包括事件循环机制、线程模型等,帮助开发者更好地理解和使用Mina。 ##### 3.4 Mina的线程模型配置 - 解释了Mina中线程模型的配置方法,包括如何合理分配线程资源以达到最佳性能。...
- **传输层**:探讨Mina支持的不同传输协议及其工作原理,例如APR传输和串行传输等。 ### Part II - MINA Core核心 #### Chapter 8 - IoBuffer - **IoBuffer详解**:IoBuffer是Mina用于高效内存管理的数据结构,...