有些时候在开发cs应用的时候,服务端需要知道哪些在线和不在线,如果服务端用的是java框架,则可以使用此文章中的示例,这里只用到了mina的很基本的功能,没有使用到其他的高级的功能,主要是实现每多长时间检测一次是否接收到客户端的消息,以及客户端断开后的处理,实现类型在线状态的功能。
1、Server类
缓冲区默认是64字节,一般的服务只需要发送很短的消息,所以用默认的大小就可以了。
package com.qinyi.sitetv.main;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.ResourceBundle;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class HearbeatServer {
private static final int PORT = 9123;
public static void main(String[] args) throws IOException {
ResourceBundle bundle = ResourceBundle.getBundle("config");
String idleTime = bundle.getString("idle_time");
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
acceptor.setHandler(new HearbeatHandler() );
//acceptor.getSessionConfig().setReadBufferSize( 2048 );
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, Integer.valueOf(idleTime) );
acceptor.bind(new InetSocketAddress(PORT));
}
}
2、消息处理类
package com.qinyi.sitetv.main;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.log4j.Logger;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import com.google.gson.Gson;
import com.qinyi.sitetv.main.service.HearbeatService;
import com.qinyi.sitetv.main.util.HttpClientUtil;
public class HearbeatHandler extends IoHandlerAdapter {
private Logger log = Logger.getLogger(this.getClass());
private ResourceBundle bundle = ResourceBundle.getBundle("config");
private static final List<String> orgCodeList;
private static Map<String, Long> org2sessionMap = new HashMap<String, Long>();
private static Map<Long, String> session2orgMap = new HashMap<Long, String>();
private static Map<Long, String> session2record = new HashMap<Long, String>();
private HearbeatService hearbeatService = new HearbeatService();
static {
orgCodeList = new ArrayList<String>();
initOrgCodeList();
}
@SuppressWarnings("unchecked")
private static void initOrgCodeList() {
String url = ResourceBundle.getBundle("config").getString("xxx");
HttpClientUtil hc = new HttpClientUtil(url, null);
String result = hc.get();
Gson gson = new Gson();
List<Map<String, String>> list = gson.fromJson(result, List.class);
for (Map<String, String> map : list) {
orgCodeList.add(map.get("org_code"));
}
}
@Override
public void sessionCreated(IoSession session) throws Exception {
log.debug("session " + session.getId() + " is created, address: " + session.getRemoteAddress());
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
cause.printStackTrace();
log.error(cause.getMessage(), cause);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
String msg = message.toString();
log.info(session.getId() + ", " + msg);
if (!orgCodeList.contains(msg.trim()) || "quit".equals(msg)) {
session.close(true);
log.debug("session id " + session.getId() + ", msg is not available, will be close.");
return;
}
if (!org2sessionMap.containsKey(msg)) {
org2sessionMap.put(msg, session.getId());
session2orgMap.put(session.getId(), msg);
String recordId = hearbeatService.onlineStart(msg);
if (recordId != null && !"".equals(recordId) ) {
session2record.put(session.getId(), recordId);
log.debug("sessionId: " + session.getId() + " =======> recordId: " + recordId);
}
}
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
log.debug("session id: " + session.getId() + ", idle count: " + session.getIdleCount(status));
int maxIdleCount = Integer.valueOf(bundle.getString("max_idle_count"));
//如果超过最大次数没有接收到消息,则关闭连接
if (session2orgMap.get(session.getId()) == null && session.getIdleCount(status) > maxIdleCount) {
session.close(true);
log.debug("session id " + session.getId() + ", no msg received, will be close.");
return;
}
if (session.getIdleCount(status) > maxIdleCount) {
onlineEnd(session);
session.close(true);
log.debug("session id " + session.getId() + ", no msg received, will be close.");
return;
}
}
@Override
public void sessionClosed(IoSession session) throws Exception {
log.debug("session " + session.getId() + " is closed");
String orgCode = session2orgMap.get(session.getId());
if (orgCode != null && !"".equals(orgCode)) {
onlineEnd(session);
}
}
private void onlineEnd(IoSession session) {
String orgCode = session2orgMap.get(session.getId());
String recordId = session2record.get(session.getId());
session2orgMap.remove(session.getId());
org2sessionMap.remove(orgCode);
session2record.remove(session.getId());
hearbeatService.onlineEnd(recordId);
}
}
详细使用可参考:http://blog.youkuaiyun.com/defonds/article/details/17996123