mina 断网之后的一系列问题 ,mina linux 系统下的问题
使用mina作为通讯的服务端,一开始的一个月用的挺好的,结果这在Linux系统下面出现了打开文件数过多的情况。
然后仔细看程序,感觉是客户端断网和断电导致在服务端的session没有被关闭,所以才会再Linux系统下出现打开文件数过多的情况。由于所以改动要求在服务端完成,所以我在项目中进行了如下操作:
这是配置文件
<!-- session config -->
<bean id="sessionConfig" factory-bean="ioAcceptor"
factory-method="getSessionConfig" >
<property name="bothIdleTime" value="${idle.timeout}"/>
<property name="receiveBufferSize" value="${receiveBufferSize}"/>
<property name="writeTimeout" value="${writeTimeout}"></property>
</bean>
<!-- 开始运行socket服务 -->
<bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor" init-method="bind" destroy-method="unbind">
<property name="defaultLocalAddress" ref="address" />
<property name="handler" ref="serverHandler" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
<property name="reuseAddress" value="true" />
</bean>
下面是具体的处理类
@Service
public class ServerHandler extends IoHandlerAdapter {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private AppUserService appUserService;
@Autowired
private AppMessageService appMessageService;
@Resource
private Map<String, MessageTask> tasks;
@Value("${offline.timeout}")
private String offline_timeout;
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
super.exceptionCaught(session, cause);
String username = (String) session.getAttribute(Constants.APPUSERNAME);
logger.error("exceptionCaught:" + cause.getMessage() + "用户:" + username);// 日志输出
session.close(true);
// session.getService().dispose();
}
/**
* 接收发过来的请求 根据key的值,看是什么协议过来
*/
// 接收客户端新的消息的时候调用
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
super.messageReceived(session, message);
byte[] bytes = (byte[]) message;
IoBuffer buffer = IoBuffer.wrap(bytes);// wrap 取前面两个的协议号
short key = buffer.getShort();
String head = ShortUtilsByteConvert.shortToString(key);
MessageTask task = tasks.get(String.valueOf(key));
logger.info("message received: " + head + "");
if (task == null) {
logger.error("unknow message received: " + head);
return;
}
task.executeReceived(buffer, session);
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
super.sessionIdle(session, status);
logger.info("Session sessionIdle" + "***********************" + status);
String username = (String) session.getAttribute(Constants.APPUSERNAME);
long last = (Long) session.getAttribute(Constants.TIMESTAMP);
long offset = System.currentTimeMillis() - last;
// System.out.println("sessionIdle " + username + " " + offset);
if (username == null) {
logger.info("userName is null*******************");
if (offset > Integer.parseInt(offline_timeout)) {// 当前时间和登陆的时间之差大于超时时间
session.write(IoBuffer.wrap("timeout\r\n".getBytes()));
session.close(false);
} else {// 没大过超时时间
session.write(IoBuffer.wrap("are you still here?\r\n".getBytes()));
}
} else {
String msg = "are you still here?\r\n";
// 写消息到客户端!
session.write(IoBuffer.wrap(msg.getBytes()));
logger.info("userName isn't null*******************" + username);
}
}
@Override
public void sessionOpened(IoSession session) throws Exception {
super.sessionOpened(session);
logger.info("Session sessionOpened...");
}
/**
* 发送完消息调用的事件
*/
@Override
public void messageSent(IoSession session, Object message) {
}
/**
* 当一个客户端连接到服务器的时候被调用
*
* @throws Exception
*/
@Override
public void sessionCreated(IoSession session) throws Exception {
super.sessionCreated(session);
logger.info("Session created...");
}
@Override
public void sessionClosed(IoSession session) throws Exception {
super.sessionClosed(session);
String appUserName = (String) session.getAttribute(Constants.APPUSERNAME);
if (appUserName == null) {
return;
}
// 根据用户名查询出一个对象
try {
if (!StringUtil.isEmpty(appUserName)) {
AppUser appUser = appUserService.findOneByAppUserName(appUserName);
if (appUser != null && !StringUtil.isEmpty(appUser.getAppUserName())) {
appUser.setUserStatus("3");// 表示退出登录
appUserService.save(appUser);// 用户退出时进行了修改状态
} else {
logger.debug("mina的sessionClosed时,app客户查询失败!");
}
MessageFactory.unregisterSession(appUserName);
}
} catch (Exception e) {
logger.debug("mina的sessionClosed时候出现了异常");
// TODO: handle exception
e.printStackTrace();
}
}
}
这样做的原理是这样的,如果客户端的session断开了,我一直发送消息,过一会就会报错,如果报错,我就在exceptionCaught()方法中关闭这个链接。
好吧!我欢天喜地的改好了,把项目放到Linux系统上去测试,结果失望了,就是客户的session是断网,断电的,我在sessionIdle()方法中不停的写也不会报错,不报错我就无法关闭连接,所以小女子在此跪求大神帮忙解决
跪求啊!项目急!