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的用法及原理進行簡單瞭解。程式還有其他程式碼沒有貼上來,全部由三部分組成,服務端、客戶端、公共元件。公共元件提供服務端、客戶端公共使用的部分,如訊息,訊息佇列,訊息模型等。如需要程式原始碼,聯絡我的郵件獲取。