Mina框架 open to many file 错误原因以及解决方案

来源:互联网 发布:c语言需要掌握 编辑:程序博客网 时间:2024/06/05 06:14

前几天用Mina2.0创建了一个tcp c/s架构的程序,可以实现客户端与服务器的长连接,方便向客户端反向推送一些消息。

项目的演示地址在:http://182.254.136.237:8080/RoomControllerServerCore/management/list.jsp


经过一天晚上的压力测试,服务器端表现非常的完美,客户端的上线,正常下线与不正常下线都能立即检测的到,踢掉客户端功能也运行正常。问题就在于我的Pad端,Android5.1系统,x86架构,昂达的Pad,出现了问题。一夜之后wifi就无法连接了,用adb勉强连上Pad logcat一下发现system_process进程一直在尝试重新连接已经保存的无线,可是最终都会报出一个错误:无法得到文件描述符。于是我使用adb shell 连进Adnroid内核shell,lsof一下,发现打印出来的列表n多,当时我的内心是崩溃的,不过心里也有点小高兴,因为我找到了问题的所在,有可能= =。。

问题出在我的代码上。

修改之前的代码:

package core;import java.net.InetSocketAddress;import org.apache.mina.core.future.ConnectFuture;import org.apache.mina.core.service.IoConnector;import org.apache.mina.core.service.IoHandler;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.keepalive.KeepAliveFilter;import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;import org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler;import org.apache.mina.transport.socket.nio.NioSocketConnector;import base.Global;public class TcpClient extends Thread{private final static boolean DEBUG = true;private IoConnector conn = null;private IoSession session = null;private IoHandler handler = null;private ClientStatus clientStatus = ClientStatus.IDLE;private InetSocketAddress inetAddress = null;public TcpClient() {// init minaconn = new NioSocketConnector();conn.setConnectTimeoutMillis(1000 * 60); conn.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MessageCodecFactory()));/** 主角登场 */  KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();  KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory, IdleStatus.BOTH_IDLE);  /** 是否回发 */  heartBeat.setForwardEvent(true);  /** 发送频率 */  heartBeat.setRequestInterval(15);  // connector.getSessionConfig().setKeepAlive(true);  conn.getFilterChain().addLast("heartbeat", heartBeat);  if(null == handler) {handler = new DefaultClientHandler();}conn.setHandler(handler);  start();}public IoSession getSession() {return session;}@Overridepublic void run() {for(;;) {try {switch (clientStatus) {case IDLE:break;case RUNNING:if(DEBUG) {System.out.println("Connecting...");}// conn = new NioSocketConnector();  ConnectFuture future = conn.connect(inetAddress);// ��������  future.awaitUninterruptibly();// �ȴ����Ӵ������  session = future.getSession();// ���session  Global.cr.onSessionOk(session);if(DEBUG) {System.out.println("Connected !");}session.getCloseFuture().awaitUninterruptibly();// �ȴ����ӶϿ�  if(DEBUG) {System.out.println("Disconnected ~");}session.close(false);// conn.dispose(); break;case QUIT:return ;default:break;}}catch(Exception e) {e.printStackTrace();continue ;} finally {try {Thread.sleep(1000 * 1);} catch (InterruptedException e) {e.printStackTrace();}}}}/** *  * @param inetAddress * @return */public boolean connect(InetSocketAddress inetAddress, IoHandler handler) {this.inetAddress = inetAddress;this.handler = handler;conn.setHandler(handler);if(clientStatus == ClientStatus.RUNNING) {return false;} else if(clientStatus == ClientStatus.IDLE) {clientStatus = ClientStatus.RUNNING;return true;} else if(clientStatus == ClientStatus.QUIT) {return false;}return true;}@SuppressWarnings("deprecation")public boolean disconnect() {if(clientStatus == ClientStatus.RUNNING) {clientStatus = ClientStatus.IDLE;session.close();return true;}return false;}public boolean send(String msg) {if(null != session && session.isConnected())session.write(msg);return true;}public static class DefaultClientHandler extends IoHandlerAdapter {@Overridepublic void exceptionCaught(IoSession session, Throwable cause) throws Exception {// TODO Auto-generated method stubsuper.exceptionCaught(session, cause);}@Overridepublic void messageReceived(IoSession session, Object message) throws Exception {System.out.println(message.toString());super.messageReceived(session, message);}@Overridepublic void messageSent(IoSession session, Object message) throws Exception {// TODO Auto-generated method stubsuper.messageSent(session, message);}@Overridepublic void sessionClosed(IoSession session) throws Exception {// TODO Auto-generated method stubsuper.sessionClosed(session);}@Overridepublic void sessionCreated(IoSession session) throws Exception {// TODO Auto-generated method stubsuper.sessionCreated(session);}@Overridepublic void sessionIdle(IoSession session, IdleStatus status) throws Exception {// TODO Auto-generated method stubsuper.sessionIdle(session, status);}/* * (non-Javadoc) * @see org.apache.mina.core.service.IoHandlerAdapter#sessionOpened(org.apache.mina.core.session.IoSession) */@Overridepublic void sessionOpened(IoSession session) throws Exception {// TODO Auto-generated method stubsuper.sessionOpened(session);}}private enum ClientStatus{RUNNING,IDLE,QUIT}private static class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {  /*  * (non-Javadoc)  *  * @see  * org.apache.mina.filter.keepalive.KeepAliveMessageFactory#getRequest  * (org.apache.mina.core.session.IoSession)  */  @Override  public Object getRequest(IoSession session) {  //        i++;  //        Log.d("session",i+"");  //      if (i > 5) {  //          try {  //                Log.d("session","睡眠");  //              Thread.sleep(40000);  //          } catch (InterruptedException e) {  //              // TODO Auto-generated catch block  //              e.printStackTrace();  //          }  //      }  return "HRT";  }  /*  * (non-Javadoc)  *  * @see  * org.apache.mina.filter.keepalive.KeepAliveMessageFactory#getResponse  * (org.apache.mina.core.session.IoSession, java.lang.Object)  */  @Override  public Object getResponse(IoSession session, Object request) {  return null;  }  /*  * (non-Javadoc)  *  * @see  * org.apache.mina.filter.keepalive.KeepAliveMessageFactory#isRequest  * (org.apache.mina.core.session.IoSession, java.lang.Object)  */  @Override  public boolean isRequest(IoSession session, Object message) {  return false;  }  /*  * (non-Javadoc)  *  * @see  * org.apache.mina.filter.keepalive.KeepAliveMessageFactory#isResponse  * (org.apache.mina.core.session.IoSession, java.lang.Object)  */  @Override  public boolean isResponse(IoSession session, Object message) {  /*if (message instanceof HEARTBEATRESPONSE) {              // Log.d("session","是响应心跳包");              return true;          }  */if(message.equals("RES"))return true;  return false;}  }  /***  * @ClassName: KeepAliveRequestTimeoutHandlerImpl  * @Description: 当心跳超时时的处理,也可以用默认处理 这里like  */  private static class KeepAliveRequestTimeoutHandlerImpl implements KeepAliveRequestTimeoutHandler {  /*  * (non-Javadoc)  *  * @seeorg.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler#  * keepAliveRequestTimedOut  * (org.apache.mina.filter.keepalive.KeepAliveFilter,  * org.apache.mina.core.session.IoSession)  */  @Override  public void keepAliveRequestTimedOut(KeepAliveFilter filter, IoSession session) throws Exception {  // ((Logger) LOG).info("心跳超时!");  }  }  public static void main(String[] args) {// for test TcpClient tcpc = new TcpClient();tcpc.connect(new InetSocketAddress("localhost", 5678), null);}}

问题出在这里

case RUNNING:if(DEBUG) {System.out.println("Connecting...");}// conn = new NioSocketConnector();  ConnectFuture future = conn.connect(inetAddress);// ��������  future.awaitUninterruptibly();// �ȴ����Ӵ������  session = future.getSession();// ���session  Global.cr.onSessionOk(session);if(DEBUG) {System.out.println("Connected !");}session.getCloseFuture().awaitUninterruptibly();// �ȴ����ӶϿ�  if(DEBUG) {System.out.println("Disconnected ~");}session.close(false);// conn.dispose(); break;

当客户端主动或者异常掉线后,此阻塞函数会throw  a new exception,之后代码的执行会直接跳进catch里面而不会继续执行未完成的代码。这就造成了NIOConnector一直无法被disposed掉,今儿导致session内部的socket占用的文件描述符无法被释放。


经过我的一番修正,应该是解决了这个问题,具体代码如下:【这里只简单写写核心的代码】

public class TcpClient extends Thread{private final static boolean DEBUG = true;private IoConnector conn = null;private IoSession session = null;private IoHandler handler = null;private ClientStatus clientStatus = ClientStatus.IDLE;private InetSocketAddress inetAddress = null;public TcpClient() {start();}public IoSession getSession() {return session;}@Overridepublic void run() {for(;;) {try {switch (clientStatus) {case IDLE:break;case RUNNING:if(DEBUG) {System.out.println("Connecting...");}// init minaconn = new NioSocketConnector();conn.setConnectTimeoutMillis(1000 * 60); conn.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MessageCodecFactory()));/** 主角登场 */  KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();  KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory, IdleStatus.BOTH_IDLE);  /** 是否回发 */  heartBeat.setForwardEvent(true);  /** 发送频率 */  heartBeat.setRequestInterval(15);  // connector.getSessionConfig().setKeepAlive(true);  conn.getFilterChain().addLast("heartbeat", heartBeat);  if(null == handler) {handler = new DefaultClientHandler();}conn.setHandler(handler);  ConnectFuture future = conn.connect(inetAddress);// ��������  future.awaitUninterruptibly();// �ȴ����Ӵ������  session = future.getSession();// ���session  Global.cr.onSessionOk(session);if(DEBUG) {System.out.println("Connected !");}session.getCloseFuture().awaitUninterruptibly();// �ȴ����ӶϿ�  if(DEBUG) {System.out.println("Disconnected ~");}break;case QUIT:return ;default:break;}}catch(Exception e) {e.printStackTrace();continue ;} finally {if(null != session)session.close(false);if(null != conn)conn.dispose();try {Thread.sleep(100 * 1);} catch (InterruptedException e) {e.printStackTrace();}}}}/** *  * @param inetAddress * @return */public boolean connect(InetSocketAddress inetAddress, IoHandler handler) {this.inetAddress = inetAddress;this.handler = handler;if(clientStatus == ClientStatus.RUNNING) {return false;} else if(clientStatus == ClientStatus.IDLE) {clientStatus = ClientStatus.RUNNING;return true;} else if(clientStatus == ClientStatus.QUIT) {return false;}return true;}@SuppressWarnings("deprecation")public boolean disconnect() {if(clientStatus == ClientStatus.RUNNING) {clientStatus = ClientStatus.IDLE;session.close();return true;}return false;}public boolean send(String msg) {if(null != session && session.isConnected())session.write(msg);return true;}public static class DefaultClientHandler extends IoHandlerAdapter {@Overridepublic void exceptionCaught(IoSession session, Throwable cause) throws Exception {// TODO Auto-generated method stubsuper.exceptionCaught(session, cause);}@Overridepublic void messageReceived(IoSession session, Object message) throws Exception {System.out.println(message.toString());super.messageReceived(session, message);}@Overridepublic void messageSent(IoSession session, Object message) throws Exception {// TODO Auto-generated method stubsuper.messageSent(session, message);}@Overridepublic void sessionClosed(IoSession session) throws Exception {// TODO Auto-generated method stubsuper.sessionClosed(session);}@Overridepublic void sessionCreated(IoSession session) throws Exception {// TODO Auto-generated method stubsuper.sessionCreated(session);}@Overridepublic void sessionIdle(IoSession session, IdleStatus status) throws Exception {// TODO Auto-generated method stubsuper.sessionIdle(session, status);}/* * (non-Javadoc) * @see org.apache.mina.core.service.IoHandlerAdapter#sessionOpened(org.apache.mina.core.session.IoSession) */@Overridepublic void sessionOpened(IoSession session) throws Exception {// TODO Auto-generated method stubsuper.sessionOpened(session);}}private enum ClientStatus{RUNNING,IDLE,QUIT}}


0 0