mina 的TCP服务端
mina 用于接收bytes消息处理的服务端
做过简单测试,其他 blog 说的串包,丢包,跳包什么的还没测过。 因为只是心血来潮用来做模拟第三方测试桩用的,有兴趣的可以测一下跳包什么的问题。
maven 引入
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.1.3</version>
</dependency>
如果是 springboot 的容器,丢工程的启动类里面就可以随工程启动服务了。
自定义业务处理的handler
package com.primeton.etc.tools;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.transport.socket.SocketSessionConfig;
import java.io.IOException;
public class MinaMyIoHandlerAdapter extends IoHandlerAdapter {
public MinaMyIoHandlerAdapter() {
}
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
// 用 IoBuffer 取, 就不用 decoder 了。
IoBuffer bbuf = (IoBuffer) message;
byte[] bytes = new byte[bbuf.limit()];
bbuf.get(bytes, bbuf.position(), bbuf.limit());
byte[] responseMsgBytes = null;
//TODO 业务处理
responseMsgBytes = bytes;
//返回数据 , 将返回报文返回给客户端 当封装成 IoBuffer 时, 不需要自定义的 encoder
IoBuffer buffer = IoBuffer.allocate(responseMsg.length);
buffer.put(responseMsg);
buffer.flip();
session.write(buffer);
//这里千万不能加 session.closeNow()
}
@Override
public void sessionClosed(IoSession session) throws Exception {
super.sessionClosed(session);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
cause.printStackTrace();
session.closeNow();
}
@Override
public void messageSent(IoSession iosession, Object obj) throws Exception {
super.messageSent(iosession, obj);
}
@Override
public void sessionCreated(IoSession iosession) throws Exception {
super.sessionCreated(iosession);
SocketSessionConfig cfg = (SocketSessionConfig) iosession.getConfig();
cfg.setReceiveBufferSize(2 * 1024 * 1024);
cfg.setReadBufferSize(2 * 1024 * 1024);
cfg.setKeepAlive(true);
cfg.setSoLinger(0); //解决可能会很多 time_wait
}
@Override
public void sessionIdle(IoSession iosession, IdleStatus idlestatus)
throws Exception {
super.sessionIdle(iosession, idlestatus);
//超时处理吧, 当session 有 5*idletime 的实际时, 服务端主动关闭
if (iosession.getIdleCount(idlestatus) == 5){
iosession.closeNow();
}
}
@Override
public void sessionOpened(IoSession iosession) throws Exception {
super.sessionOpened(iosession);
}
}
服务类
package com.primeton.etc.tools;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MinaServer {
private NioSocketAcceptor acceptor = null;
public MinaServer(int port) throws IOException {
acceptor = new NioSocketAcceptor();
// 设置读取数据的缓冲区大小
acceptor.getSessionConfig().setReadBufferSize(1024*102400);
// 读写通道10秒内无操作进入空暇状态
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
//绑定一个日志处理器
acceptor.getFilterChain().addLast("logger",new LoggingFilter());
//绑定业务处理 handler
acceptor.setHandler(new MinaMyIoHandlerAdapter());
//绑定端口
acceptor.bind(new InetSocketAddress(port));
System.out.println("TCP服务启动,端口:" + port);
}
//测试启动
public static void main(String[] args) throws IOException {
new MinaServer(10000);
}
}
测试类 java socket
public static Serializable sendMessage(String ip,int port,int timeout,Serializable msg){
Socket socket = null;
InputStream is = null;
OutputStream os = null;
try {
InetAddress addr = InetAddress.getByName(ip);
socket = new Socket();
socket.connect(new InetSocketAddress(addr,port),timeout);
System.out.println("socket 连接成功 ");
socket.setSendBufferSize(102400);
is = socket.getInputStream();
os = socket.getOutputStream();
os.write(String.format("%04d",((byte[])msg).length).getBytes());
os.write((byte[])msg);
System.out.println("写收据到etc成功 ");
os.flush();
byte[] head = new byte[4];
System.out.println(is.available());
is.read(head,0,4);
int nlen = Integer.parseInt(new String(head));
System.out.println("nlen = "+nlen);
byte[] bytes = new byte[nlen];
is.read(bytes,0,nlen);
System.out.println("接收返回收据成功:" + new String(bytes));
os.close();
is.close();
socket.close();
return conect(head,bytes);
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (os != null){
os.close();
}
if (is != null){
is.close();
}
if (socket != null){
socket.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
return null;
}
public static void main(String[] args) {
byte[] msg = "asdag".getBytes();
SocketUtil.sendMessage("127.0.0.1",10000,60000,msg);
}