Mina介绍
Mina可以用于快速的开发基于网络通信的应用,特别是在开发手机端的游戏应用时,使用的较为普遍。本文简单介绍了一个用Mina搭建的一个简易讨论组,通过该应用可以对Mina的基本用法用途有个大致的了解。
界面效果
界面元素不多,使用了两个AWT组件。
客户端1:
客户端2:
服务端日志:
核心代码
服务端Handler
1: /**
2: * <服务端消息Handler>
3: *
4: * @author liping.action@gmail.com
5: * @version V1.0
6: */
7: public class ServerMessageHandler extends IoHandlerAdapter {
8: private MsgQueue msgQueueReceived;
9: private MsgQueue msgQueueSent;
10:
11: public MsgQueue getMsgQueueReceived() {
12: return msgQueueReceived;
13: }
14:
15: public void setMsgQueueReceived(MsgQueue msgQueueReceived) {
16: this.msgQueueReceived = msgQueueReceived;
17: }
18:
19: public MsgQueue getMsgQueueSent() {
20: return msgQueueSent;
21: }
22:
23: public void setMsgQueueSent(MsgQueue msgQueueSent) {
24: this.msgQueueSent = msgQueueSent;
25: }
26:
27: static {
28: PropertyConfigurator.configure(ClassLoader
29: .getSystemResource("log4j.properties"));
30: }
31: private static Logger logger = Logger.getLogger(ServerMessageHandler.class);
32:
33: @Override
34: public void exceptionCaught(IoSession session, Throwable cause)
35: throws Exception {
36: logger.error(cause.toString());
37: }
38:
39: @Override
40: public void messageReceived(IoSession session, Object message)
41: throws Exception {
42: Msg msg = (Msg) message;
43: logger.info("MSG:from=" + session.getRemoteAddress() + ",id="
44: + msg.getId() + ",content=" + msg.getContent());
45: Collection<IoSession> sessions = session.getService()
46: .getManagedSessions().values();
47: msg.setId(session.getRemoteAddress().toString());
48: for (IoSession ioSession : sessions) {
49: ioSession.write(msg);
50: }
51: }
52:
53: @Override
54: public void messageSent(IoSession session, Object message) throws Exception {
55: logger.info(Constant.MESSAGE_SENT);
56: }
57:
58: @Override
59: public void sessionClosed(IoSession session) throws Exception {
60: logger.info(Constant.SESSION_CLOSED);
61: }
62:
63: @Override
64: public void sessionCreated(IoSession session) throws Exception {
65: logger.info(Constant.SESSION_CREATED);
66: }
67:
68: @Override
69: public void sessionIdle(IoSession session, IdleStatus status)
70: throws Exception {
71: logger.info(Constant.SESSION_IDLE);
72: }
73:
74: @Override
75: public void sessionOpened(IoSession session) throws Exception {
76: logger.info(Constant.SESSION_OPENED);
77: logger.info("address : "
78: + session.getRemoteAddress());
79: }
80:
81: }
客户端handler
1: /**
2: * <客户端handler>
3: *
4: * @author liping.action@gmail.com
5: * @version V1.0
6: */
7: public class ClientMessageHanlder extends IoHandlerAdapter {
8: private static Logger logger = Logger.getLogger(ClientMessageHanlder.class);
9: private MsgModel msgModel;
10:
11: public MsgModel getMsgModel() {
12: return msgModel;
13: }
14:
15: public void setMsgModel(MsgModel msgModel) {
16: this.msgModel = msgModel;
17: }
18:
19: @Override
20: public void exceptionCaught(IoSession session, Throwable cause)
21: throws Exception {
22: super.exceptionCaught(session, cause);
23: }
24:
25: @Override
26: public void messageReceived(IoSession session, Object message)
27: throws Exception {
28: Msg msg = (Msg) message;
29: logger.info("msg:id=" + msg.getId() + ",content=" + msg.getContent());
30: msgModel.setMsg(msg);
31: msgModel.fireModelChange();//触发模型变更,通知观察者
32: }
33:
34: @Override
35: public void messageSent(IoSession session, Object message) throws Exception {
36: super.messageSent(session, message);
37: }
38:
39: @Override
40: public void sessionClosed(IoSession session) throws Exception {
41: super.sessionClosed(session);
42: }
43:
44: @Override
45: public void sessionCreated(IoSession session) throws Exception {
46: super.sessionCreated(session);
47: }
48:
49: @Override
50: public void sessionIdle(IoSession session, IdleStatus status)
51: throws Exception {
52: super.sessionIdle(session, status);
53: }
54:
55: @Override
56: public void sessionOpened(IoSession session) throws Exception {
57: Msg msg = new Msg(session.getRemoteAddress().toString(),
58: session.getLocalAddress() + " " + DateUtil.getCurrentData() + " 进入了讨论组!");
59: session.write(msg);
60: }
61: }
服务端启动器:
1: /**
2: * 服务端启动器
3: *
4: */
5: public class ServerLauncher {
6: static {
7: PropertyConfigurator.configure(ClassLoader
8: .getSystemResource("log4j.properties"));
9: }
10: private static Logger logger = Logger.getLogger(ServerMessageHandler.class);
11:
12: public static void main(String[] args) {
13: // 创建一个非阻塞的server端Socket ,用NIO
14: SocketAcceptor acceptor = new NioSocketAcceptor();
15: // 创建接收数据的过滤器
16: DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
17: // 设定这个过滤器将以对象为单位读取数据
18: ProtocolCodecFilter filter = new ProtocolCodecFilter(
19: new ObjectSerializationCodecFactory());
20: chain.addLast("objectFilter", filter);
21: // 设定服务器消息处理器
22: acceptor.setHandler(new ServerMessageHandler());
23: // 服务器绑定的端口
24: int bindPort = 9988;
25: // 绑定端口,启动服务器
26: try {
27: acceptor.bind(new InetSocketAddress(bindPort));
28: } catch (IOException e) {
29: logger.error(e.toString());
30: }
31: logger.info("Mina Server run done! on port:" + bindPort);
32: }
33: }
客户端启动器:
1: /**
2: * 客户端启动器
3: *
4: */
5: public class ClientLauncher {
6: static {
7: PropertyConfigurator.configure(ClassLoader
8: .getSystemResource("log4j.properties"));
9: }
10:
11: public static void main(String[] args) {
12: // 创建消息模型(被观察者)
13: MsgModel model = new MsgModel();
14: // 创建一个tcp/ip 连接
15: NioSocketConnector connector = new NioSocketConnector();
16: /*---------接收对象---------*/
17: // 创建接收数据的过滤器
18: DefaultIoFilterChainBuilder chain = connector.getFilterChain();
19: // 设定这个过滤器将以对象为单位读取数据
20: ProtocolCodecFilter filter = new ProtocolCodecFilter(
21: new ObjectSerializationCodecFactory());
22: chain.addLast("objectFilter", filter);
23: ClientMessageHanlder hanlder = new ClientMessageHanlder();
24: hanlder.setMsgModel(model);
25: // 设定客户端端的消息处理器
26: connector.setHandler(hanlder);
27: // Set connect timeout.
28: connector.setConnectTimeoutCheckInterval(30);
29: // 连结到服务器:
30: final ConnectFuture cf = connector.connect(new InetSocketAddress(
31: "127.0.0.1", 9988));
32: createComponent(model, cf);
33: cf.awaitUninterruptibly();
34: cf.getSession().getCloseFuture().awaitUninterruptibly();
35: connector.dispose();
36: }
37:
38: private static void createComponent(MsgModel model, final ConnectFuture cf) {
39: JFrame frame = new JFrame("Client");
40: frame.setLocation(450, 300);
41: final TextField textField = new TextField();
42:
43: textField.addKeyListener(new KeyListener() {
44: public void keyTyped(KeyEvent arg0) {
45: }
46:
47: public void keyReleased(KeyEvent arg0) {
48: }
49:
50: public void keyPressed(KeyEvent arg0) {
51: if (arg0.getKeyCode() == KeyEvent.VK_ENTER) {
52: String value = textField.getText();
53: if (!value.equals("")) {
54: Msg msg = new Msg("0002", value);
55: cf.getSession().write(msg);
56: textField.setText("");
57: }
58: }
59: }
60: });
61: // 自定义TextArea
62: CusTextArea textArea = new CusTextArea();
63: model.addObserver(textArea);
64: frame.setSize(300, 450);
65: frame.setResizable(false);
66: frame.setBackground(Color.white);
67: frame.add(textField, BorderLayout.SOUTH);
68: frame.add(textArea, BorderLayout.NORTH);
69: frame.pack();
70: frame.setVisible(true);
71: frame.addWindowListener(new CloseHandler(cf.getSession()));
72: textField.requestFocus();
73: }
74: }
结语
该应用为一个简单的讨论组程序,可实现多人讨论,说白了是重复造轮子,但通过此应用可以对mima的用法及原理进行简单了解。程序还有其他代码没有贴上来,全部由三部分组成,服务端、客户端、公共组件。公共组件提供服务端、客户端公共使用的部分,如消息,消息队列,消息模型等。如需要程序源码,联系我的邮件获取。