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
来源:oschina
链接:https://my.oschina.net/u/2963604/blog/3161391