Mina出现问题:Don't know how to handle message of type 'java.lang.String'

限于喜欢 提交于 2020-02-27 04:48:00

Mina在做心跳实验时,客户端出现java.lang.IllegalStateException: Don't know how to handle message of type 'java.lang.String'.  Are you missing a protocol encoder? 帖子 https://blog.csdn.net/xiaoborui20110806/article/details/41075075 中说mina不知道如何处理string,要在connector增加一个ProtocolCodecFilter,我的客户端源代码:

public class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {
    Logger logger = LoggerFactory.getLogger(this.getClass());
    /** 心跳包内容  刚好和服务器相反*/
    private static final String CLIENTHEARTBEATREQUEST = "1112";//客户端发
    private static final String CLIENTHEARTBEATRESPONSE = "1111";//客户端收的服务端信息
//    原文链接:https://blog.csdn.net/hannuotayouxi/article/details/78685334

    public String ioBufferToString(IoBuffer iobuffer) {
        System.out.println("message = " + iobuffer + iobuffer.limit());
//        iobuffer.flip(); // 调换buffer当前位置,并将当前位置设置成0
        if(iobuffer.limit() == 0)
            return "";
        byte[] by = new byte[iobuffer.limit()];
        iobuffer.get(by);
        StringBuffer stringBuffer = new StringBuffer();

        for (int i = 0; i < by.length; i++) {
            stringBuffer.append((char) by[i]); // 可以根据需要自己改变类型
        }
        return stringBuffer.toString();
    }
    /***
     * 接收到服务端发来的消息进行判断是否是心跳包消息
      * @param ioSession
     * @param msg
     * @return
     */
    @Override
    public boolean isRequest(IoSession ioSession, Object msg) {
        String s = ioBufferToString((IoBuffer)msg);
        if(s.equals(CLIENTHEARTBEATRESPONSE))
        {
            logger.info("接收到服务端心跳数据包,引发心跳事件,心跳数据包内容是"+s);
            return true;
        }
        logger.info("接收到的服务端心跳数据包并不正确"+s);
        return false;
    }

    /**
     * 判断客户端发的消息是否是心跳响应消息
     * @param ioSession
     * @param msg
     * @return
     */
    @Override
    public boolean isResponse(IoSession ioSession, Object msg) {
        String s = ioBufferToString((IoBuffer)msg);
        if(s.equals(CLIENTHEARTBEATREQUEST))
        {
            logger.info("客户端要发的是心跳数据包"+s);
        }
        logger.info("客户端要发的不是心跳数据包"+s);
        return false;
    }

    /**
     * 返回要发给服务端的消息
     * @param ioSession
     * @return
     */
    @Override
    public Object getRequest(IoSession ioSession) {
        return CLIENTHEARTBEATREQUEST;
    }

    /**
     * 接收到服务端发来的消息
     * @param ioSession
     * @param request
     * @return
     */
    @Override
    public Object getResponse(IoSession ioSession, Object request) {
        logger.info("接收到的服务端消息:"+request.toString());
        return request;
    }
}

public class KeepAliveRequestTimeoutHandlerImpl implements KeepAliveRequestTimeoutHandler {
    Logger logger = LoggerFactory.getLogger(this.getClass());
    @Override
    public void keepAliveRequestTimedOut(KeepAliveFilter keepAliveFilter, IoSession ioSession) throws Exception {
        logger.info("《*客户端*》心跳包发送超时处理(及长时间没有发送(接受)心跳包)");
    }
}
public class ClinetHandler extends IoHandlerAdapter {
    Logger logger = LoggerFactory.getLogger(this.getClass());
    private static final String CLIENTHEARTBEATREQUEST = "1112";//客户端发
    private static final String CLIENTHEARTBEATRESPONSE = "1111";//客户端收的服务端信息
    @Override
    public void sessionCreated(IoSession session) throws Exception {
        super.sessionCreated(session);
    }

    /**
     * 连接
     * @param session
     * @throws Exception
     */
    @Override
    public void sessionOpened(IoSession session) throws Exception {
        logger.info("ClinetHandler.sessionOpened"+session.getRemoteAddress().toString());
        super.sessionOpened(session);
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        logger.info("ClinetHandler.sessionClosed"+session.getRemoteAddress().toString());
        super.sessionClosed(session);
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        if(status == IdleStatus.READER_IDLE)
        {
            logger.info("ClinetHandler.sessionIdle==READER_IDLE");
        }
        else if(status == IdleStatus.WRITER_IDLE)
        {
            logger.info("ClinetHandler.sessionIdle==WRITER_IDLE");
        }
        else if(status == IdleStatus.BOTH_IDLE)
        {
            logger.info("ClinetHandler.sessionIdle==BOTH_IDLE");
        }
        super.sessionIdle(session, status);
    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        logger.info("ClinetHandler.exceptionCaught"+cause.getMessage());
        super.exceptionCaught(session, cause);
    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        logger.info("ClinetHandler.messageReceived=="+message);
//        super.messageReceived(session, message);
        if(CLIENTHEARTBEATREQUEST == (String)message)
        {
            session.write(message);
        }
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        logger.info("ClinetHandler.messageSent=="+message);
        super.messageSent(session, message);
    }

    @Override
    public void inputClosed(IoSession session) throws Exception {
        super.inputClosed(session);
    }

    @Override
    public void event(IoSession session, FilterEvent event) throws Exception {
        super.event(session, event);
    }
}
public class ClientThread implements Runnable {
    public NioSocketConnector ioConnector;
    /** 30秒后超时 */
    private static final int IDELTIMEOUT = 30;
    /** 15秒发送一次心跳包 */
    private static final int HEARTBEATRATE = 15;
    private IoSession session;
    @Override
    public void run() {

        ioConnector = new NioSocketConnector();
//        ioConnector.getSessionConfig().setReadBufferSize(1024);
//        ioConnector.getSessionConfig().setBothIdleTime();
//        ioConnector.setConnectTimeoutMillis(IDELTIMEOUT * 1000);
//        ioConnector.getFilterChain().addFirst("codcel1",new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),LineDelimiter.WINDOWS.getValue())));
        KeepAliveRequestTimeoutHandlerImpl keepAliveRequestTimeoutHandler = new KeepAliveRequestTimeoutHandlerImpl();
        KeepAliveMessageFactoryImpl keepAliveMessageFactory = new KeepAliveMessageFactoryImpl();
        //new 心跳filter(keepAliveFilter)时需要超时处理handler,哪种状态的超时,消息工厂
        //消息工厂messageFactory最重要,工厂里面有四种方法,isRequest(是否对方心跳请求),isRespone(是否发送的心跳回复),
        // getRequest(得到要发送给对方的消息),getRespone(得到对方发来的消息)
        KeepAliveFilter keepAliveFilter = new KeepAliveFilter(keepAliveMessageFactory, IdleStatus.BOTH_IDLE,keepAliveRequestTimeoutHandler);
        //还要设置如果是心跳数据包是否到下一个filter
        keepAliveFilter.setForwardEvent(false);
        //设置心跳频率
        keepAliveFilter.setRequestInterval(HEARTBEATRATE);
        //将心跳filter放入ioConnector
        ioConnector.getFilterChain().addFirst("keepalivefilter",keepAliveFilter);
//        ioConnector.getFilterChain().addLast("systemwriterfilter",new SystemW);
        //设置业务功能模块handler
        ioConnector.setHandler(new ClinetHandler());
        //启动ioconnector的心跳机制
//        ioConnector.getSessionConfig().setKeep
//        ioConnector.getSessionConfig().
        //设置ioconnector的idle时间
        ioConnector.getSessionConfig().setIdleTime(IdleStatus.READER_IDLE,45);
        ConnectFuture connectFuture = ioConnector.connect(new InetSocketAddress(7080));
        connectFuture.awaitUninterruptibly();//??????
        session = connectFuture.getSession();
//        connect(ioConnector);
        for(;;);
    }

}

我在ClientThread.run方法中添加ProtocolCodecFilter,添加位置如下:

ioConnector.getFilterChain().addFirst("codecforkeepalivestring",new ProtocolCodecFilter(new TextLineCodecFactory()));
KeepAliveRequestTimeoutHandlerImpl keepAliveRequestTimeoutHandler = new KeepAliveRequestTimeoutHandlerImpl();

OK

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!