1 mina体系结构
1 mina在应用程序中的地位
主要屏蔽了网络通信的一些细节,对socket进行封装,并且是NIO的一个实现框架,可以帮助我们快速的开发网络通信,常常用于用户游戏的开发,中间件等服务端程序;
2 IoServer接口
用于描述服务端和客户端的抽象;其子类IoAcceptor代表了服务端;其子类IoConnector代表了客户端;
Ioprocesser多线程环境来处理我们的连接请求流程;
IoFilter提供数据的过滤工作:包括编码、解码、日志等信息的过滤(执行在handler之前)
Handler就是我们的业务对象,自定义的Handler需要实现IoHandler(推荐继承 IoHandlerAdapter)
IoSession:就是对客户端和服务端链接的描述;常常用于发送和接受数据;主要提供对链接的管理(读取数据、发送数据、设置会话的上下文)
关系结构 、 流程顺序: IoAccepter —> IoProcesser —> IoFilter —> handler | IoSession | IoConnector —> IoProcesser —> IoFilter —> handler
2 示例1(简单示例)
mina的简单使用很常见,网上搜一下就行了;我这里有一个当时调用建设银行接口的代码 (只是客户端)
1 关键点:
- 自己写的handler 业务处理类
- 使用mina自带的行解码器(我们没有用换行符去做分割,用的是 【】)
- 编写客户端
2 handler 业务处理类
实际上重写了也是多余,啥也没干; ```java package com.yjyz.pay.core.srv.pay.platform.ccb.mina;
import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession;
/**
- FileName: ClientHander
- Autho: binC
Date: 2022/3/22 14:07 */ public class ClientHander extends IoHandlerAdapter {
@Override public void sessionCreated(IoSession session) throws Exception {
System.out.println(
"client与:" + session.getRemoteAddress().toString() + "建立连接");
}
@Override public void sessionOpened(IoSession session) throws Exception {
System.out.println("打开连接");
}
@Override public void sessionClosed(IoSession session) throws Exception {
System.out.println( "client与:" + session.getRemoteAddress().toString() + "断开连接");
}
@Override public void sessionIdle(IoSession session, IdleStatus status)
throws Exception { System.out.println("IDLE " + session.getIdleCount(status));
}
@Override public void exceptionCaught(IoSession session, Throwable cause)
throws Exception { cause.printStackTrace();
}
@Override public void messageReceived(IoSession session, Object message)
throws Exception { System.out.println("client接受信息:" + message.toString());
}
@Override public void messageSent(IoSession session, Object message)
throws Exception { System.out.println("client发送信息:" + message.toString());
}
}
<a name="cpg3w"></a>
#### 3 客户端工具类
```java
package com.yjyz.pay.core.srv.pay.platform.ccb.mina;
import com.yjyz.core.exceptions.BusinessRtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.ReadFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
/**
* FileName: CcbClient
* Autho: binC
* Date: 2022/3/22 14:09
*/
// @Component
@Slf4j
public class CcbClient {
public int PORT = 18088;//默认值
// public static final String IP = "127.0.0.1";
public String IP = "111.111.111.111"; //默认值
//
private SocketConnector connector;
private ConnectFuture future;
private IoSession session;
private String lindelimit_end = "</TX>";
public CcbClient() {
}
public CcbClient(String IP, int PORT) {
this.PORT = PORT;
this.IP = IP;
}
public static void main(String[] args) throws Exception {
String ip = "111.111.111.111";
int port = 18088;
CcbClient client = new CcbClient(ip, port);
String send = client.send("<?xml version=\"1.0\" encoding=\"GB2312\" standalone=\"yes\" ?><TX><REQUEST_SN>942596935052087424</REQUEST_SN><CUST_ID>客户号12312</CUST_ID><USER_ID>userid456456</USER_ID><PASSWORD>密码123456</PASSWORD><TX_CODE>6W0100</TX_CODE><LANGUAGE>CN</LANGUAGE><TX_INFO><ACC_NO>52050150383600000006</ACC_NO></TX_INFO></TX>");
System.out.println(send);
}
public boolean connect() {
/*
* 1.创建一个socket连接,连接到服务器
*/
connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(5000);
/*
* 获取过滤器链,用于添加过滤器
*/
DefaultIoFilterChainBuilder chain = connector.getFilterChain();
// b.添加日志过滤器
chain.addLast("logger", new LoggingFilter());
// c.添加字符的编码过滤器
chain.addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory(
Charset.forName("GB18030"),
LineDelimiter.DEFAULT.getValue(),
lindelimit_end)));
// chain.addLast("codec", new ProtocolCodecFilter(new PrefixedStringCodecFactory(Charset.forName("UTF-8"))));
/*
* 3.设置消息处理器,用于处理接收到的消息 用的是自己的handler
*/
connector.setHandler(new ClientHander());
/*
* 4.根据IP和端口号连接到服务器
*/
future = connector.connect(new InetSocketAddress(IP, PORT));
// 等待连接创建完成
future.awaitUninterruptibly();
/*
* 5.获取session对象,通过session可以向服务器发送消息;
*/
session = future.getSession();
session.getConfig().setUseReadOperation(true);
// catch (Exception e) {
// e.printStackTrace();
// log.error("建立与建行的链接失败:"+e.getMessage());
// throw e;
// }
return future.isConnected();
}
/**
* 往服务器发送消息
*
* @param message
*/
public void sendMsg2Server(String message) {
session.write(message);
}
/**
* 关闭与服务器的连接
*
* @return
*/
public boolean close() {
if (session != null) {
session.getCloseFuture().awaitUninterruptibly(); //等待关闭连接
}
if (connector != null) {
connector.dispose();
}
return true;
}
public String send(String message) throws Exception {
String res = null;
try {
connect();
sendMsg2Server(message);
ReadFuture readFuture = session.read().awaitUninterruptibly();
res = (String) readFuture.getMessage() + lindelimit_end;
// System.out.println("------------------>" + res );
} finally {
close();
}
return res;
}
}
3 示例2 (自定义协议包的)
这个相对复杂了一些;我将代码放到了gitee上;自行去看吧,项目地址 【https://gitee.com/binC_2016/getServiceImpls/blob/master/src/main/java/com/binc/testspring/study/mina/study2/MyClient.java】
study2包就是自定协议包的全部内容了,包含了服务端和客户端;
study1包是一个简单的服务端和客户端;比 (示例1)[https://www.yuque.com/binc/java/oa4r25#vVkoF] 好点 ;