简单玩mina的socekt的服务端和客户端,自定义事务处理器&监听器&心跳监听

1.项目结构

最好自己在翻一番源码,本人研究了2天netty但是没有研究明白发现这两款框架与很多相似之处,比如
netty的默认线程数为cpu核数*2,但是也自己可以根据构造传入线程数
mina的默认线程数为cpu核数+1,但是没找到从哪里可以传入线程数,有大佬可以回一下

netty主要针对的是channel
mina主要针对的是session

等等,这俩框架还在研究中,
mima有很多默认的实现,但是大多数支持重写
有什么问题可以讨论,我也多学习学习,我也可以把我研究netty的记录发出来

也可以看看官网api
http://mina.apache.org/mina-project/userguide/ch1-getting-started/ch1.4-first-steps.html
在这里插入图片描述

2.maven依赖

<dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.6</version>
            <type>jar.sha256</type>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.rxtx</groupId>
            <artifactId>rxtx</artifactId>
            <version>2.1.7</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.mina</groupId>
            <artifactId>mina-core</artifactId>
            <version>2.0.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

3.日志管理(必配)

log4j.properties

###set log levels -for more verbose logging change 'info' to 'debug'###
log4j.rootLogger=info,stdout,file
###direct log messages to stdout###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

###direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=D://log//mina//mina.log

log4j.appender.file.MaxFileSize=10240KB
## Keep one backup file
log4j.appender.file.MaxBackupIndex=1

log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%p %t %c - %m%n

服务端

MyServer.java

package com.mina.test.firstdemo;

import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.service.IoService;
import org.apache.mina.core.service.IoServiceListener;
import org.apache.mina.core.session.IdleStatus;
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.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

public class MyServer {

    private final static Logger log = LoggerFactory.getLogger(MyServer.class);

    public static void main(String[] args) throws IOException {

        /**  Io流接收者(socket服务端) 默认开启线程数为cpu盒数*2 */
        IoAcceptor acceptor = new NioSocketAcceptor();

        try {

            /** 设置缓冲区buffer大小 */
            acceptor.getSessionConfig().setReadBufferSize(2048);

            /** 读写通道10秒内无操作进入空闲状态*/
            acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);

            /** 自定义服务器事务处理器*/
            acceptor.setHandler(new MyServerHandler());

            /** 自定义服务器监听器 */
            acceptor.addListener(new MyListener());

            /** 自定义心跳监听器*/

            KeepAliveFilter kaf = new KeepAliveFilter(new KeepAliveMessageFactoryImpl());

            /** 这个还没有搞懂*/
            kaf.setRequestTimeoutHandler(new MyKeepAliveRequestTimeoutHandler());

            /** 设置心跳监听执行时间 单位秒*/
            kaf.setRequestInterval(1);

            /** 把心跳监听器加入(注册)到 服务器里*/
            acceptor.getFilterChain().addLast("heart", kaf);

            /** 把日志加入(注册)到 服务器 不加会报错*/
            acceptor.getFilterChain().addLast("logger", new LoggingFilter());

            /** 设置服务器的 解码格式*/
            acceptor.getFilterChain().addLast("codec",
                    new ProtocolCodecFilter(
                            new TextLineCodecFactory(Charset.forName("UTF-8")
                                    , LineDelimiter.WINDOWS.getValue(),LineDelimiter.WINDOWS.getValue())));

            /** 服务器绑定ip 和 端口号 或者叫监听的端口*/
            acceptor.bind(new InetSocketAddress("127.0.0.1",6666));
            log.info("服务端已开启!!!!!!!!!!!!!!!");
        } catch (IOException e) {
            e.printStackTrace();

        }finally {

        }


    }

}


/**
 *@Description 事务处理器
 *@Author Mr.CongShuo
 *@Date 2021/3/10 0010
 *@Time 17:03
 */

class MyServerHandler extends IoHandlerAdapter {

    /** 定义日志*/
    private final static Logger log = LoggerFactory.getLogger(MyServerHandler.class);

    /** 定义客户端关闭编码*/
    private final static String QUIT = "quit";

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {

        String str = message.toString();

        log.info("this message received is [" + str + "]");
        if(QUIT.equals(str)) {
            session.close(true);
            return;
        }
    }

    /** 事务处理器 */
    public MyServerHandler() {

    }

    /** 客户端 连接监听 函数 当有客户端走了以后会在线程池里的selector 下的fdMap 注册 也就是session会话
     *
     *  创建新连接后,从I / O处理器线程调用。 因为应该从处理多个会话的I / O的同一线程中调用此方法,
     *  所以请实现此方法以执行消耗最少时间的任务,例如套接字参数和用户定义的会话属性初始化
     **/
    @Override
    public void sessionCreated(IoSession session) throws Exception {
        super.sessionCreated(session);
        System.out.println("==============" + Thread.currentThread().getName());
        System.out.println("客户端为: " +session.getId() + "进来了");

    }

    /**
     * 当建立完成后 会打开一个通道
     * @param session
     * @throws Exception
     */
    @Override
    public void sessionOpened(IoSession session) throws Exception {
        session.write("恭喜你来了");
    }

    /**
     * 客户端关闭会调用这个函数
     * @param session
     * @throws Exception
     */
    @Override
    public void sessionClosed(IoSession session) throws Exception {
        System.out.println("线程为:" + Thread.currentThread().getName() +" 的,sessionId为:" + session.getId() + "的客户端关闭了");
    }

    /**
     * 限制状态处理
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        System.out.println("线程为:" + Thread.currentThread().getName() +" 的,sessionId为:" + session.getId() + "的客户端进入了闲置状态");
    }

    /**
     * 异常状态处理
     * @param session
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        System.out.println("线程为:" + Thread.currentThread().getName() +" 的,sessionId为:" + session.getId() + "的客户端处理发生了异常 " + cause.getMessage());
    }

    /***
     * 向客户端发送数据
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        System.out.println("向 线程为:" + Thread.currentThread().getName() +" 的,sessionId为:" + session.getId() + "的客户端处理发送数据");

    }


}

/**
 *@Description 监听器
 *@Author Mr.CongShuo
 *@Date 2021/3/10 0010
 *@Time 17:03
 */

class MyListener implements IoServiceListener {

    @Override
    public void serviceActivated(IoService service) throws Exception {
        System.out.println("thread-name :" + Thread.currentThread().getName());
        System.out.println("我被激活了");
    }

    @Override
    public void serviceIdle(IoService service, IdleStatus idleStatus) throws Exception {
        System.out.println("thread-name :" + Thread.currentThread().getName());
        System.out.println("我现在没事干了");
    }

    @Override
    public void serviceDeactivated(IoService service) throws Exception {
        System.out.println("thread-name :" + Thread.currentThread().getName());
        System.out.println("我现在被停用了");
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        System.out.println("thread-name :" + Thread.currentThread().getName());
        System.out.println("建立新回话  有人已经进来了 准备唠嗑了");
    }

    /***
     * 当有客户端走了以后会在线程池里的selector 下的fdMap 删除 也就是注册到 线程池里的session会话
     * @param session
     * @throws Exception
     */
    @Override
    public void sessionDestroyed(IoSession session) throws Exception {
        System.out.println("thread-name :" + Thread.currentThread().getName());
        System.out.println("销毁回话  有人走了");
        long id = session.getId();
        CloseFuture closeFuture = session.close(true);
        boolean closed = closeFuture.isClosed();
        if(closed){
            System.out.println("客户端 sessionId为: " + id + " 关闭成功");
            closeFuture.setClosed();
        }else{
            System.out.println("客户端 sessionId为:" + id + "关闭失败");
        }

    }
}


/**
 *@Description 心跳包
 *@Author Mr.CongShuo
 *@Date 2021/3/10 0010
 *@Time 17:04
 */
class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {

    @Override
    public boolean isRequest(IoSession session, Object message) {
        System.out.println("====isRequest=====");
        return false;
    }

    @Override
    public boolean isResponse(IoSession session, Object message) {
        System.out.println("======是否能相应客户端=======" +  (null == message   ? "" : message.toString()));
        return  session.isConnected();
    }

    @Override
    public Object getRequest(IoSession session) {
        System.out.println("======是否能请求到客户端======");
        return null;
    }

    @Override
    public Object getResponse(IoSession session, Object request) {
        System.out.println("=====getResponse=====");
        return null;
    }



}

class MyKeepAliveRequestTimeoutHandler implements  KeepAliveRequestTimeoutHandler{

    @Override
    public void keepAliveRequestTimedOut(KeepAliveFilter filter, IoSession session) throws Exception {
        System.out.println(session.getId() + "走了");
    }
}

客户端

package com.mina.test.firstdemo;

import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
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.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.nio.NioSocketConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.Scanner;

public class MyClient {
    private final static Logger log = LoggerFactory.getLogger(MyClient.class);

    public static void main(String[] args) {
        IoConnector connector = new NioSocketConnector();
        try {
            connector.getSessionConfig().setReadBufferSize(2048);
            connector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 5);
            connector.setHandler(new MyClientHandler());
            connector.getFilterChain().addLast("logger", new LoggingFilter());
            connector.getFilterChain().addLast("codec",
                    new ProtocolCodecFilter(
                            new TextLineCodecFactory(Charset.forName("UTF-8")
                                    , LineDelimiter.WINDOWS.getValue(),LineDelimiter.WINDOWS.getValue())));
            ConnectFuture connectFuture = connector.connect(new InetSocketAddress("127.0.0.1", 6666));
            connectFuture.awaitUninterruptibly();
            log.info("服务端已开启!!!!!!!!!!!!!!!");
            IoSession session = connectFuture.getSession();
            Scanner sc = new Scanner(System.in);
            boolean quit = false;
            while (!quit) {
                String str = sc.next();
                if (str.equalsIgnoreCase("quit")) {
                    quit = true;
                }
                session.write(str);
            }

            if (session != null) {
                if (session.isConnected()) {
                    session.getCloseFuture().awaitUninterruptibly();
                }

                connector.dispose(true);
            }

        } catch (Exception e) {

            e.printStackTrace();

        }finally {

        }
    }

}

class MyClientHandler extends IoHandlerAdapter {
    /** 定义日志*/
    private final static Logger log = LoggerFactory.getLogger(MyClientHandler.class);
    @Override
    public void messageSent(IoSession arg0, Object message) throws Exception {
        System.out.println("客户端收到信息" + message.toString());
    }

    public MyClientHandler() {

    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {

    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {

    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {

    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {

    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {

    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        String str = message.toString();

        log.info("this message received is [" + str + "]");
    }
}

还有功能没有研究到 可以探究

这个文章写得也挺好
https://blog.csdn.net/defonds/article/details/18315563

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值