Spring Boot集成 mina 服务端搭建

Spring Boot集成 mina 服务端搭建

        <!--Mina框架依赖 -->
        <dependency>
            <groupId>org.apache.mina</groupId>
            <artifactId>mina-core</artifactId>
            <version>2.0.2</version>
        </dependency>```

package com.example.netty;

import javax.annotation.PostConstruct;





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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class ServerHandler extends IoHandlerAdapter {

private Logger logger = LoggerFactory.getLogger(this.getClass());


	/* 在本类中调用其他service需要使用以下方法
	 *
	 * */

	//1.声明service类
	/*@Autowired
	private TbBoxService tbBoxService;*/

    private static ServerHandler serverHandler ;

    //2通过@PostConstruct实现初始化bean之前进行的操作
    @PostConstruct
    public void init() {
        serverHandler = this;
        //serverHandler.tbBoxService = this.tbBoxService;.
        //3.调用时需要加前缀 如 serverHandler.tbBoxService
    }


	@Override
	public void sessionCreated(IoSession session) throws Exception { //用户连接到服务器
		SocketSessionConfig cfg = (SocketSessionConfig) session.getConfig();
		cfg.setSoLinger(0);
		logger.info("[服务建立]" + session.getId());
	}

    @Override
    public void messageReceived(IoSession session, Object message)throws Exception {//接收消息 收到消息可以自己定义处理类或者转发
    	IoBuffer bbuf = (IoBuffer) message;
        byte[] byten = new byte[bbuf.limit()];
        bbuf.get(byten, bbuf.position(), bbuf.limit());
        String str = new String(byten);

        logger.info("[收到消息]" + str);
	}


    @Override
	public void sessionClosed(IoSession session) throws Exception {   //用户从服务器断开
    	logger.info("[服务断开]" + session.getId());

	}
    @Override
    public void messageSent(IoSession session, Object message){ //发送消息结束
    	logger.info("[发送消息结束]" + session.getId() + "message" + message);
    }


    @Override
    public void sessionIdle(IoSession session, IdleStatus status)throws Exception {//重连
    	logger.info("[服务重连]" + session.getId() + "status" + status.toString());
    }


	@Override
    public void exceptionCaught(IoSession session, Throwable cause)throws Exception {//连接发生异常
		cause.printStackTrace();
        logger.info("[服务异常]" + session.getId());
    }
}

Spring boot 启动类直接加入启动项目时自动启动服务
 @Bean
    public IoAcceptor ioAcceptor() throws Exception {
        // 创建一个非阻塞的server端的Socket
        IoAcceptor acceptor = new NioSocketAcceptor();
        // 添加日志过滤器
        acceptor.getFilterChain().addLast("logger", new LoggingFilter());
//        acceptor.getFilterChain().addLast("codec",
//                new ProtocolCodecFilter(new HCoderFactory(Charset.forName("UTF-8"))));
// 自定义解编码器  HCoderFactory
//配置之后需要自己编码或者解码下面有具体代码 配置和可解决粘包问题
        // 设置Handler
        acceptor.setHandler(new ServerHandler());
        // 设置读取数据的缓存区大小
        acceptor.getSessionConfig().setReadBufferSize(2048);
        // 读写通道10秒内无操作进入空闲状态
        acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
        try {
            // 绑定端口
            acceptor.bind(new InetSocketAddress(8085));
            System.out.println("服务端在:" + 8085 + "端口启动");
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return acceptor;
    }
package mina;

import java.nio.charset.Charset;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
/**
 * 编码和解码器工厂类
 * @author admin
 *
 */
public class HCoderFactory implements ProtocolCodecFactory {

	private final HEncoder encoder;
	private final HDecoder decoder;
 
	public HCoderFactory() {
		this(Charset.forName("UTF-8"));
 
	}
 
	public HCoderFactory(Charset charSet) {
		this.encoder = new HEncoder(charSet);
		this.decoder = new HDecoder(charSet);
	}
 
	@Override
	public ProtocolDecoder getDecoder(IoSession arg0) throws Exception {
		return decoder;
	}
 
	@Override
	public ProtocolEncoder getEncoder(IoSession arg0) throws Exception {
		return encoder;
	}

}

package mina;

import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 解码工具类
 * @author admin
 *
 */
public class HDecoder extends CumulativeProtocolDecoder {
	private final Charset charset;
	private static final Logger log = LoggerFactory.getLogger(HEncoder.class);
	 
	public HDecoder(Charset charset) {
		this.charset = charset;
	}

	@Override
	protected boolean doDecode(IoSession ioSession, IoBuffer ioBuffer, ProtocolDecoderOutput protocolDecoderOutput)
			throws Exception {
		// 丢包,断包处理
		if (ioBuffer.remaining() > 4)// 有包头,包头足够
		{
			ioBuffer.mark();// 标记当前position的快照标记mark,以便后继的reset操作能恢复position位置,开始是0
			byte[] l = new byte[4];
			ioBuffer.get(l);// 读取包头,占4个字节
			if (ioBuffer.remaining() < 4)// 内容长度的4个字节不够,断包
			{
				ioBuffer.reset();
				return false;//
			} else {// 内容长度的4个字节数组足够
				byte[] bytesLegth = new byte[4];// 内容长度
				ioBuffer.get(bytesLegth);// 读取内容长度,int类型,占四个字节
				int len = byteArrayToInt(bytesLegth);// 内容长度有多少
				if (ioBuffer.remaining() < len)// 内容不够,断包
				{
					ioBuffer.reset();
					return false;//

				} else { // 消息内容足够

					byte[] bytes = new byte[len];
					ioBuffer.get(bytes, 0, len);
					protocolDecoderOutput.write(new String(bytes, charset));// 读取内容,并且发送

					if (ioBuffer.remaining() < 4) {// 包尾不够
						ioBuffer.reset();
						return false;//

					} else {// 包尾足够
						byte[] tails = new byte[4];
						ioBuffer.get(tails);// 读取包尾
						if (ioBuffer.remaining() > 0)// 最后如果粘了包,会再次调用doDeocde()方法,把剩余数据给doDeocde()方法处理
						{
							return true;
						}

					}
				}

			}

		}
		return false;// 断包,或者执行完,
	}

	public static int byteArrayToInt(byte[] bytes) {
		int value = 0;
		// 由高位到低位
		for (int i = 0; i < 4; i++) {
			int shift = (4 - 1 - i) * 8;
			value += (bytes[i] & 0x000000FF) << shift;// 往高位游
		}
		return value;
	}
}

package mina;

import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 编码工具类
 */
public class HEncoder implements ProtocolEncoder {
	private static final Logger log = LoggerFactory.getLogger(HEncoder.class);
	private final Charset charset;
	 
	public HEncoder(Charset charset) {
		this.charset = charset;
	}

	/**
	 * 直接将数据发出去,数据格式,包头+消息长度(int)+消息内容(json字符串)+包尾 包头包尾是十六进制字符串00 aa bb cc,转化成字节数组0,
	 * -86, -69, -52四个字节
	 *
	 * @param session
	 * @param message
	 * @param out
	 * @throws Exception
	 */
	@Override
	public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
		// 仿项目,解决断包,粘包问题
		String value = (message == null ? "" : message.toString());// 消息值
		log.info(value);
		byte[] content = value.getBytes(charset);// 消息内容,字节数组
		IoBuffer buf = IoBuffer.allocate(38 + content.length).setAutoExpand(true);// 缓冲区容量大小38字节加上字符长度
		buf.put(new byte[] { 0, -86, -69, -52 });// 输入包开头固定值十六进制00 aa bb cc,转化成字节数组
		buf.putInt(content.length);// int为4字节,一个字节等于2个16进制字符,所以有八位 00 00 00 0c,内容长度。
		buf.put(content);// 消息内容
		buf.put(new byte[] { 0, -86, -69, -52 });// 包尾
		buf.flip();
		out.write(buf);// 写入
	}

	@Override
	public void dispose(IoSession session) throws Exception {
		log.info("Dispose called,session is " + session);
	}

}

测试 启动项目后 再写一个客户端即可测试(暂未配置编码 解码) 客户端编码 解码需要自行实现
    public static void main(String[] args) {
    	  try { 
    	      // 连接到服务器 
    	      Socket socket = new Socket("127.0.0.1", 8085);  
    	      try { 
    	        // 向服务器端发送信息的DataOutputStream 
    	        OutputStream out = socket.getOutputStream(); 
    	        // 装饰标准输入流,用于从控制台输入 
    	        Scanner scanner = new Scanner(System.in); 
    	        while (true) { 
    	          String send = scanner.nextLine(); 
    	          System.out.println("客户端:" + send); 
    	          byte[] by = send.getBytes("UTF-8");
    	          by = send.getBytes();//把字符串转换成数组
    	          out.write(by); 
    	          out.flush(); 
    	          // 把从控制台得到的信息传送给服务器 
    	          // out.writeUTF("客户端:" + send); 
    	          // 读取来自服务器的信息 
    	        } 
    	  
    	      } finally { 
    	        socket.close(); 
    	      } 
    	    } catch (IOException e) { 
    	      e.printStackTrace(); 
    	    } 
    	  } 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值