mina2官方例证chat服务器
mina2官方例子chat服务器
这是chat服务器里面的main方法入口:
这是协议命令:
这是chatProtocolhandler
这是chat服务器里面的main方法入口:
package org.apache.mina.example.chat; import java.net.InetSocketAddress; import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory; 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.filter.logging.MdcInjectionFilter; import org.apache.mina.filter.ssl.SslFilter; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; /** * (<b>Entry point</b>) Chat server * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class Main { /** 服务器端口号 */ private static final int PORT = 1234; /** 是否启用ssl */ private static final boolean USE_SSL = false; public static void main(String[] args) throws Exception { //实例化一个NioSocketAcceptor NioSocketAcceptor acceptor = new NioSocketAcceptor(); //获取过滤器链 DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); //实例化MdcInjectionFilter过滤器,针对日志输出做MDC操作,可以参考log4j的MDC、NDC的文档 MdcInjectionFilter mdcInjectionFilter = new MdcInjectionFilter(); //添加MdcInjectionFilter过滤器 chain.addLast("mdc", mdcInjectionFilter); //如果开启ssl,则添加ssl支持过滤链 if (USE_SSL) { addSSLSupport(chain); } /* 添加TextLine编解码过滤器,将一行以换行符为结束符号的byte[]转换成String对象 * TextLineCodecFactory有TextLineEncoder编码实现,TextLineDecoder解码实现 */ chain.addLast("codec", new ProtocolCodecFilter( new TextLineCodecFactory())); //添加日志过滤器 addLogger(chain); // 设置handler acceptor.setHandler(new ChatProtocolHandler()); //绑定服务器端口 acceptor.bind(new InetSocketAddress(PORT)); System.out.println("Listening on port " + PORT); } /** * 添加ssl支持过滤器 * @param chain 过滤器链 * @throws Exception */ private static void addSSLSupport(DefaultIoFilterChainBuilder chain) throws Exception { SslFilter sslFilter = new SslFilter(BogusSslContextFactory .getInstance(true)); chain.addLast("sslFilter", sslFilter); System.out.println("SSL ON"); } /** * 添加日志过滤器 * @param chain 过滤器链 * @throws Exception */ private static void addLogger(DefaultIoFilterChainBuilder chain) throws Exception { chain.addLast("logger", new LoggingFilter()); System.out.println("Logging ON"); } }
这是协议命令:
package org.apache.mina.example.chat; /** * Encapsulates a chat command. Use {@link #valueOf(String)} to create an * instance given a command string. * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class ChatCommand { public static final int LOGIN = 0;//登录 public static final int QUIT = 1;//退出 public static final int BROADCAST = 2;//广播 private final int num; private ChatCommand(int num) { this.num = num; } public int toInt() { return num; } /* * */ public static ChatCommand valueOf(String s) { s = s.toUpperCase(); if ("LOGIN".equals(s)) { return new ChatCommand(LOGIN); } if ("QUIT".equals(s)) { return new ChatCommand(QUIT); } if ("BROADCAST".equals(s)) { return new ChatCommand(BROADCAST); } throw new IllegalArgumentException("Unrecognized command: " + s); } }
这是chatProtocolhandler
package org.apache.mina.example.chat; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.apache.mina.core.service.IoHandler; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.logging.MdcInjectionFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@link IoHandler} implementation of a simple chat server protocol. * * @author <a href="http://mina.apache.org">Apache MINA Project</a> */ public class ChatProtocolHandler extends IoHandlerAdapter { private final static Logger LOGGER = LoggerFactory.getLogger(ChatProtocolHandler.class); //客户端session Set集合 private final Set<IoSession> sessions = Collections .synchronizedSet(new HashSet<IoSession>()); //用户 Set集合 private final Set<String> users = Collections .synchronizedSet(new HashSet<String>()); /** * 异常处理 */ @Override public void exceptionCaught(IoSession session, Throwable cause) { LOGGER.warn("Unexpected exception.", cause); //如果有未捕获的异常则关闭连接 session.close(true); } /** * 接收信息处理 */ @Override public void messageReceived(IoSession session, Object message) { Logger log = LoggerFactory.getLogger(ChatProtocolHandler.class); log.info("received: " + message); //转换成String类型 String theMessage = (String) message; //以空格分隔成两半 String[] result = theMessage.split(" ", 2); //前半段是协议命令 String theCommand = result[0]; try { //转换成协议命令对象 ChatCommand command = ChatCommand.valueOf(theCommand); //从session取得key为user的值 //取得当前用户 String user = (String) session.getAttribute("user"); switch (command.toInt()) { //退出 case ChatCommand.QUIT: session.write("QUIT OK"); session.close(true); break; //登录 case ChatCommand.LOGIN: //session里有用户已登录 if (user != null) { session.write("LOGIN ERROR user " + user + " already logged in."); return; } //取得后半段的用户名 if (result.length == 2) { user = result[1]; } else { session.write("LOGIN ERROR invalid login command."); return; } //该用户已在线 //if(isChatUser(user)){ if (users.contains(user)) { session.write("LOGIN ERROR the name " + user + " is already used."); return; } //将连接添加到sessions集合中统一管理 sessions.add(session); //设置该session的user属性 session.setAttribute("user", user); //edit me MdcInjectionFilter.setProperty(session, "user", user); //将用户添加users集合中统一管理 users.add(user); //给客户端返回登录成功消息 session.write("LOGIN OK"); //通知所有现在用户有新用户登入 broadcast("The user " + user + " has joined the chat session."); break; //广播信息 case ChatCommand.BROADCAST: //取得后半段用户需要广播的信息内容,并广播 if (result.length == 2) { broadcast(user + ": " + result[1]); } break; //不认识的命令 default: LOGGER.info("Unhandled command: " + command); break; } } catch (IllegalArgumentException e) { LOGGER.debug("Illegal argument", e); } } /** * 给所有在线用户广播信息 * @param message 信息内容 */ public void broadcast(String message) { synchronized (sessions) { for (IoSession session : sessions) { if (session.isConnected()) { session.write("BROADCAST OK " + message); } } } } /** * 连接断开处理 */ @Override public void sessionClosed(IoSession session) throws Exception { String user = (String) session.getAttribute("user"); //移除用户以及连接,并通知其他在线用户该用户已离开 users.remove(user); sessions.remove(session); broadcast("The user " + user + " has left the chat session."); } /** * 判断用户是否在线 * @param name * @return */ public boolean isChatUser(String name) { return users.contains(name); } /** * 获取在线用户数 * @return 在线用户数 */ public int getNumberOfUsers() { return users.size(); } /** * 强制某用户下线 * @param name 用户名 */ public void kick(String name) { synchronized (sessions) { for (IoSession session : sessions) { if (name.equals(session.getAttribute("user"))) { session.close(true); break; } } } } }