分布式实战(干货)
spring cloud 实战(干货)
mybatis 实战(干货)
spring boot 实战(干货)
React 入门实战(干货)
构建中小型互联网企业架构(干货)
python 学习持续更新
ElasticSearch 笔记
kafka storm 实战 (干货)
scala 学习持续更新
RPC
深度学习
GO 语言 持续更新
Android 学习
nginx 相关文章
Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。与Netty出自同一人之手,都是一个介于应用程序与网络之间的NIO框架,通过Java nio技术基于TCP/IP和UDP/IP协议提供了抽象的、事件驱动的、异步的API,使程序员从繁琐的网络操作中解脱出来,花更多的时间在业务处理上。
mina分为三层,如下图:
1、IOService层:处理IO操作
2、IOFilter层:过滤器链,日志处理、字节变换、对象转换等操作
3、IOHandler层:真正的处理业务逻辑的地方
IoService
IoService用来管理各种IO服务,在mina中,这些服务可以包括session、filter、handler等
上面的图简单介绍了IoService的职责,以及其具体实现类AbstractIoService中的职责。在比较大的框架中,都是采用了大量的抽象类之间继承,采用层级实现细节这样的方式来组织代码。所以在mina中看到Abstract开头的类,并不仅仅只是一个抽象,其实里面也包含很多的实现了。
服务端IoAcceptor及相关类
IOAcceptor相当于是对ServerSocketChannel的封装,最重要的两个操作是绑定与接受连接。
Acceptor线程专门负责接受连接,在其上有一个selector,轮询是否有连接建立上来,当有连接建立上来,调用ServerSocketChannel.accept方法来接受连接,这个方法返回一个session对象,然后将这个session对象加入processor中,由processor遍历每个session来完成真正的IO操作。processor上也有一个selector与一个Processor线程,selector用于轮询session,Processor线程处理每个session的IO操作。
客户端IOConnector及相关类
IOConnector的设计与IOAcceptor几乎完全一样,唯一不同的是与Acceptor线程对应的是Connector线程,在完成连接操作后也是扔了一个session对象到Processor中。
过滤器(Filter)
下面是官网提供的过滤器
可以通过继承IoFilterAdapter来实现自己的过滤器,但一般不需要这么做,以下是一些常用的过滤器:
IoSession
Mina每建立一个连接同时会创建一个session对象,用于保存这次读写需要用到的所有信息。从抽象类AbstractIoSession中可以看出session具有如下功能:
1、从attributes成员可以看出session可以存放用户关心的键值对
2、注意到WriteRequestQueue,这是一个写请求队列,processor中调用flush或者flushNow方法时会将用户写入的数据包装成一个writeRequest对象,并加入这个队列中。
3、提供了大量的统计功能,比如接收到了多少消息、最后读取时间等
在代码中设置session:
// 创建服务器监听
IoAcceptor acceptor = new NioSocketAcceptor();
// 设置buffer的长度
acceptor.getSessionConfig().setReadBufferSize(2048);
// 设置连接超时时间
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
连接到来创建一个session,初始化好之后加入到processor负责的一个队列中。processor线程会把队列中的session对应的通道都注册到它自己的selector上,然后这个selector轮询这些通道是否准备就绪,一旦准备就绪就调用对应方法进行处理(read or flushNow)。
Mina中的session具有状态,且状态之间是可以相互转化的
IoFilter与IoHandler就是在这些状态上面加以干预,下面重点看一下IDLE状态,它分三种:
Idle for read:在规定时间内没有数据可读
Idle for write:在规定时间内没有数据可写
Idle for both:在规定时间内没有数据可读和可写
这三种状态分别对应IdleStatus类的三个常量:READER_IDLE、WRITER_IDLE、BOTH_IDLE
前面session的用法中有如下设置:
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
服务端
引入相关jar包
(1)mina-core-2.0.16.jar
(2)slf4j-api-1.7.21.jar及相关jar包
public class MinaService {
public static void main(String[] args) {
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast( "logger", new LoggingFilter() );
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
acceptor.setHandler(new DemoServiceHandler());
acceptor.getSessionConfig().setMaxReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); //10秒没有读写就进入空闲状态
try {
acceptor.bind(new InetSocketAddress(9123));
} catch (IOException e) {
e.printStackTrace();
}
}
private static class DemoServiceHandler extends IoHandlerAdapter{
@Override
public void sessionCreated(IoSession session) throws Exception {
super.sessionCreated(session);
}
@Override
public void sessionOpened(IoSession session) throws Exception {
super.sessionOpened(session);
}
@Override
public void sessionClosed(IoSession session) throws Exception {
super.sessionClosed(session);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
super.exceptionCaught(session, cause);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
super.messageReceived(session, message);
String msg = message.toString();
session.write(new Date());
System.out.println("接收到的数据:"+msg);
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
super.messageSent(session, message);
}
}
}
客户端
相关jar包
(1)mina-core-2.0.16.jar
(2)slf4j-android-1.6.1-RC1.jar
public class ConnectionManager {
private static final String BROADCAST_ACTION="com.commonlibrary.mina";
private static final String MESSAGE="message";
private ConnectionConfig mConfig;
private WeakReference mContext;
private NioSocketConnector mConnection;
private IoSession mSession;
private InetSocketAddress mAddress;
public ConnectionManager(ConnectionConfig config) {
this.mConfig = config;
this.mContext = new WeakReference(config.getContext());
init();
}
private void init() {
mAddress = new InetSocketAddress(mConfig.getIp(), mConfig.getPort());
mConnection = new NioSocketConnector();
mConnection.getSessionConfig().setReadBufferSize(mConfig.getReadBufferSize());
mConnection.getFilterChain().addLast("logger", new LoggingFilter());
mConnection.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
mConnection.setHandler(new DefaultHandler(mContext.get()));
mConnection.setDefaultRemoteAddress(mAddress);
}
public boolean connect() {
try {
ConnectFuture future = mConnection.connect();
future.awaitUninterruptibly();
mSession = future.getSession();
SessionManager.getInstance().setSeesion(mSession);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return mSession != null ? true:false;
}
public void disConnection()
{
mConnection.dispose();
mConnection = null;
mSession = null;
mAddress = null;
mContext = null;
}
private static class DefaultHandler extends IoHandlerAdapter {
private final Context mContext;
public DefaultHandler(Context context) {
this.mContext = context;
}
@Override
public void sessionCreated(IoSession session) throws Exception {
super.sessionCreated(session);
}
@Override
public void sessionOpened(IoSession session) throws Exception {
super.sessionOpened(session);
//将我们的session保存到我们的session manager类中, 从而可以发送消息到服务器
}
@Override
public void sessionClosed(IoSession session) throws Exception {
super.sessionClosed(session);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
super.messageReceived(session, message);
if (mContext != null)
{
Intent intent = new Intent(BROADCAST_ACTION);
intent.putExtra(MESSAGE, message.toString());
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
super.messageSent(session, message);
}
}
}
public class ConnectionConfig {
private Context context;
private String ip;
private int port;
private int readBufferSize;
private long connectionTimeout;
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getReadBufferSize() {
return readBufferSize;
}
public void setReadBufferSize(int readBufferSize) {
this.readBufferSize = readBufferSize;
}
public long getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(long connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
//构建者模式
public static class Builder{
private Context context;
private String ip="10.90.24.139";
private int port=9123;
private int readBufferSize=10240;
private long connectionTimeout=10000;
public Builder(Context context) {
this.context = context;
}
public Builder setIp(String ip) {
this.ip = ip;
return this;
}
public Builder setPort(int port) {
this.port = port;
return this;
}
public Builder setReadBufferSize(int readBufferSize) {
this.readBufferSize = readBufferSize;
return this;
}
public Builder setConnectionTimeout(long connectionTimeout) {
this.connectionTimeout = connectionTimeout;
return this;
}
private void applyConfig(ConnectionConfig config)
{
config.context = this.context;
config.ip = this.ip;
config.port = this.port;
config.readBufferSize = readBufferSize;
config.connectionTimeout = this.connectionTimeout;
}
public ConnectionConfig builder()
{
ConnectionConfig config = new ConnectionConfig();
applyConfig(config);
return config;
}
}
}
public class SessionManager {
private static SessionManager mInstance = null;
//最终与服务器进行通信的对象
private IoSession mSession;
public static SessionManager getInstance() {
if (mInstance == null)
{
synchronized (SessionManager.class) {
if (mInstance == null) {
mInstance = new SessionManager();
}
}
}
return mInstance;
}
public void setSeesion(IoSession session){
this.mSession = session;
}
public SessionManager() {
}
public SessionManager(IoSession mSession) {
this.mSession = mSession;
}
/**
* 将对象写到服务端
* @param msg
*/
public void writeToServer(Object msg)
{
if (mSession != null) {
mSession.write(msg);
}
}
public void closeSession()
{
if (mSession != null)
mSession.closeOnFlush();
}
public void removeSession()
{
this.mSession = null;
}
}
public class MinaActivity extends Activity implements View.OnClickListener{
private MessageBroadcastReceiver receiver = new MessageBroadcastReceiver();
private Button btn1, btn2;
private TextView message;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mina_test);
message = (TextView) findViewById(R.id.message);
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
registerBroadcast();
}
private void registerBroadcast() {
IntentFilter filter = new IntentFilter("com.commonlibrary.mina");
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
}
private void unregisterBroadcast()
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(new Intent(this, MinaService.class));
unregisterBroadcast();
}
@Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.btn1:
SessionManager.getInstance().writeToServer("123");
break;
case R.id.btn2:
Intent intent = new Intent(this, MinaService.class);
startService(intent);
break;
}
}
private class MessageBroadcastReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
message.setText(intent.getStringExtra("message"));
}
}
}
布局文件中就是两个按钮和一个文本控件,代码就不贴了。
public class MinaService extends Service {
private ConnectionHandlerThread thread;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
thread = new ConnectionHandlerThread("mina", getApplicationContext());
System.out.println("service create:");
thread.start();
}
@Override
public void onDestroy() {
super.onDestroy();
thread.disConnection();
}
/**
* 负责调用ConnectionManager
*/
class ConnectionHandlerThread extends HandlerThread {
private Context context;
boolean isConnection;
ConnectionManager mManager;
public ConnectionHandlerThread(String name, Context context) {
super(name);
this.context = context;
ConnectionConfig config = new ConnectionConfig.Builder(context)
.setIp("10.90.24.139").setPort(9123)
.setReadBufferSize(10240).setReadBufferSize(10000).builder();
System.out.println(config.getReadBufferSize());
mManager = new ConnectionManager(config);
}
@Override
protected void onLooperPrepared() {
super.onLooperPrepared();
while (true) {
isConnection = mManager.connect(); //
if (isConnection) {
break;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void disConnection() {
mManager.disConnection();
}
}
}
注意:
(1)局部广播的使用(LocalBroadcastManager)
(2)android中AlertDialog使用的构建者模式
(3)HandlerThread的使用