您的位置:首页 > 运维架构

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

2017-03-18 19:18 351 查看
前几天用Mina2.0创建了一个tcp c/s架构的程序,可以实现客户端与服务器的长连接,方便向客户端反向推送一些消息.
经过一天晚上的压力测试,服务器端表现非常的完美,客户端的上线,正常下线与不正常下线都能立即检测的到,踢掉客户端功能也运行正常。问题就在于我的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 mina
conn = 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;
}

@Override
public 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 {

@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
// TODO Auto-generated method stub
super.exceptionCaught(session, cause);
}

@Override
public void messageReceived(IoSession session, Object message) throws Exception {
System.out.println(message.toString());
super.messageReceived(session, message);
}

@Override
public void messageSent(IoSession session, Object message) throws Exception {
// TODO Auto-generated method stub
super.messageSent(session, message);
}

@Override
public void sessionClosed(IoSession session) throws Exception {
// TODO Auto-generated method stub
super.sessionClosed(session);
}

@Override
public void sessionCreated(IoSession session) throws Exception {
// TODO Auto-generated method stub
super.sessionCreated(session);
}

@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
// TODO Auto-generated method stub
super.sessionIdle(session, status);
}

/*
* (non-Javadoc)
* @see org.apache.mina.core.service.IoHandlerAdapter#sessionOpened(org.apache.mina.core.session.IoSession)
*/
@Override
public void sessionOpened(IoSession session) throws Exception {
// TODO Auto-generated method stub
super.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;
}

@Override
public void run() {
for(;;) {
try {
switch (clientStatus) {
case IDLE:
break;
case RUNNING:
if(DEBUG) {
System.out.println("Connecting...");
}
// init mina
conn = 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 {

@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
// TODO Auto-generated method stub
super.exceptionCaught(session, cause);
}

@Override
public void messageReceived(IoSession session, Object message) throws Exception {
System.out.println(message.toString());
super.messageReceived(session, message);
}

@Override
public void messageSent(IoSession session, Object message) throws Exception {
// TODO Auto-generated method stub
super.messageSent(session, message);
}

@Override
public void sessionClosed(IoSession session) throws Exception {
// TODO Auto-generated method stub
super.sessionClosed(session);
}

@Override
public void sessionCreated(IoSession session) throws Exception {
// TODO Auto-generated method stub
super.sessionCreated(session);
}

@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
// TODO Auto-generated method stub
super.sessionIdle(session, status);
}

/*
* (non-Javadoc)
* @see org.apache.mina.core.service.IoHandlerAdapter#sessionOpened(org.apache.mina.core.session.IoSession)
*/
@Override
public void sessionOpened(IoSession session) throws Exception {
// TODO Auto-generated method stub
super.sessionOpened(session);
}

}

private enum ClientStatus{
RUNNING,
IDLE,
QUIT
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐