天天看點

Java NIO簡易聊天室(二)

<b>四、</b><b>Message.java</b>

         定義的字元串消息。

<b></b>

public class Message { 

    static class MessageHolder { 

       static Message instance = new Message(); 

    } 

    public static Message getInstance() { 

       return MessageHolder.instance; 

    public static final String SEPARATOR = "`"; 

    /** 用戶端登入伺服器的消息類型,用以通知登入名等 */ 

    public static final int MSG_1 = 1; // 1`msg 

    /** 伺服器通知各用戶端新登入者資訊的消息類型 */ 

    public static final int MSG_2 = 2; // 2`msg`fromIp 

    /** 伺服器回複新登入者所有線上用戶端資訊的消息類型 */ 

    public static final int MSG_3 = 3; // 3`ip`msg`ip`msg`... 

    /** 用戶端發送所有人資訊的消息類型(或伺服器發送消息) */ 

    public static final int MSG_4 = 4; // 4`msg 

    /** 用戶端發送指定人資訊的消息類型 */ 

    public static final int MSG_5 = 5; // 5`msg`toIp`toIp`... 

    /** 伺服器轉發發送者資訊的消息類型 */ 

    public static final int MSG_6 = 6; // 6`msg`fromIp 

    /** 用戶端通知伺服器退出的消息類型 */ 

    public static final int MSG_7 = 7; // 7 

    /** 伺服器通知各用戶端退出者資訊的消息類型 */ 

    public static final int MSG_8 = 8; // 8`fromIp 

    // 構造和解析方式詳細參見附件工程了 

<b>五、</b><b>ChatServerTest.java</b>

         伺服器消息處理實作。

public class ChatServerTest implements Observer, Runnable { 

    private static final String BLANK = " "; 

    /** 線上用戶端資訊 */ 

    private HashMap&lt;InetSocketAddress, String&gt; onLineMap; 

    private ChatServer server; 

    public ChatServerTest() { 

       server = new ChatServer(8899); 

       server.addObserver(this); 

       server.start(); 

       new Thread(this).start(); 

    @Override 

    public void update(Observable o, Object arg) { 

       ChatServer server = (ChatServer) o; 

       switch (server.getStatus()) { 

       case ChatServer.SEV_ON: 

           System.out.println("伺服器開啟了"); 

           onLineMap = new HashMap&lt;InetSocketAddress, String&gt;(); 

           break; 

       case ChatServer.SEV_OFF: 

           System.out.println("伺服器關閉了"); 

           onLineMap = null; 

       case ChatServer.CLT_CONNECT: 

           // InetSocketAddress address = (InetSocketAddress) arg; 

       case ChatServer.CLT_DISCONNECT: 

           quit((InetSocketAddress) arg); 

       case ChatServer.MSG_SEND: 

           // System.out.println("通知:" 

           // + ((String) arg).split(Message.SEPARATOR)[1]); 

       case ChatServer.MSG_RECEIVE: 

           Message msg = Message.getInstance(); 

           msg.create(server.getReceiveMessage()); 

           msg.setFromIp((InetSocketAddress) arg); 

           handleMsg(msg); // 處理消息 

       case ChatServer.ERROR: 

           System.out.println("error : " + ((Exception) arg).getMessage()); 

       } 

    private void handleMsg(Message msg) { 

       int type = msg.getType(); 

       InetSocketAddress formIp = msg.getFromIp(); 

       switch (type) { 

       case Message.MSG_1: 

           System.out.println(msg.getMsg() + BLANK + msg.toIpString(formIp) 

                  + BLANK + "登入了"); 

           onLineMap.put(formIp, msg.getMsg()); 

           /* 通知所有用戶端新登入者資訊 */ 

           msg.setType(Message.MSG_2); 

           // msg.setFromIp(address); 

           server.send(msg.toString()); 

           /* 傳回登入用戶端所有線上用戶端資訊(會覆寫前一個發送給address的資訊) */ 

           msg.setType(Message.MSG_3); 

           msg.setOnLineMap(onLineMap); 

           server.send(msg.toString(), formIp); 

       case Message.MSG_4: 

           System.out.println(onLineMap.get(msg.getFromIp()) + BLANK + "said" 

                  + BLANK + msg.getMsg()); 

           msg.setType(Message.MSG_6); 

       case Message.MSG_7: 

           quit(formIp); 

    private void quit(InetSocketAddress address) { 

       if (onLineMap.get(address) != null) { 

           System.out 

                  .println(onLineMap.get(address) + BLANK 

                         + Message.getInstance().toIpString(address) + BLANK 

                         + "退出了"); 

           onLineMap.remove(address); 

           msg.setType(Message.MSG_8); 

           msg.setFromIp(address); 

    public void run() { 

       BufferedReader br = null; 

       try { 

           br = new BufferedReader(new InputStreamReader(System.in)); 

           while (true) { 

              String inputLine = br.readLine(); 

              if (inputLine.trim().toLowerCase().equals("off")) { 

                  server.close(); 

                  break; 

              } else { 

                  // 鍵盤輸入為GBK編碼,需要轉成UTF-8才可顯示。或者變為GBK工程。 

                  // 這麼轉碼仍是有問題的。例如奇數漢字“大家好”時,顯示為“大家�?”。可以看下如下網址: 

                  // http://www.blogjava.net/pengpenglin/archive/2010/02/22/313669.html 

                  inputLine = new String(inputLine.getBytes("gbk"), "utf-8"); 

                  server.send(Message.MSG_4 + Message.SEPARATOR + inputLine); 

                  System.out.println("通知:" + inputLine); 

              } 

           } 

        } catch (IOException e) { 

           e.printStackTrace(); 

       } finally { 

           try { 

              if (br != null) { 

                  br.close(); 

           } catch (IOException e) { 

              e.printStackTrace(); 

    public static void main(String[] args) { 

       new ChatServerTest(); 

<b>六、</b><b>ChatClientTest.java</b>

         用戶端消息處理實作。

public class ChatClientTest implements Observer, Runnable { 

    private String name; 

    private ChatClient client; 

    public ChatClientTest(String name) { 

       this.onLineMap = new HashMap&lt;InetSocketAddress, String&gt;(); 

       this.name = name; 

       client = new ChatClient("192.168.1.107", 8899); 

       // client = new ChatClient("127.0.0.1", 8899); 

       client.addObserver(this); 

        client.start(); 

       ChatClient client = (ChatClient) o; 

       switch (client.getStatus()) { 

       case ChatClient.CLT_CONNECT: 

           // 發送登入消息 

           Message msg1 = Message.getInstance(); 

           msg1.setType(Message.MSG_1); 

           msg1.setMsg(name); 

           client.send(msg1.toString()); 

       case ChatClient.CLT_DISCONNECT: 

           System.out.println("斷開伺服器連接配接"); 

           System.exit(1); 

       case ChatClient.MSG_SEND: 

       case ChatClient.MSG_RECEIVE: 

           msg.create((String) arg); 

       case ChatClient.ERROR: 

       case Message.MSG_2: 

           System.out.println(msg.getMsg() + BLANK 

                  + msg.toIpString(msg.getFromIp()) + BLANK + "登入了"); 

           onLineMap.put(msg.getFromIp(), msg.getMsg()); 

       case Message.MSG_3: 

           onLineMap = msg.getOnLineMap(); 

           System.out.println("連接配接上了伺服器"); 

           System.out.println("/***線上成員***/"); 

           Iterator&lt;Entry&lt;InetSocketAddress, String&gt;&gt; it = onLineMap 

                  .entrySet().iterator(); 

           while (it.hasNext()) { 

              Entry&lt;InetSocketAddress, String&gt; entry = it.next(); 

              InetSocketAddress address = entry.getKey(); 

              System.out.println(entry.getValue() + BLANK 

                     + address.getAddress().getHostAddress() + ":" 

                     + address.getPort()); 

           System.out.println("通知:" + msg.getMsg()); 

       case Message.MSG_6: 

       case Message.MSG_8: 

           InetSocketAddress address = msg.getFromIp(); 

              if (inputLine.trim().toLowerCase().equals("quit")) { 

                  client.send(Message.MSG_7 + ""); 

                  client.close(); 

                  // 參見ChatServerTest注釋 

                  client.send(Message.MSG_4 + Message.SEPARATOR + inputLine); 

       } catch (IOException e) { 

       new ChatClientTest("使用者" + new Random().nextInt(100)); 

<b>七、其他</b>

         用戶端記錄用的Map,消息就簡單定義的字元串,指定某些IP發送消息沒寫。總之不影響主要功能的,能偷懶的都盡可能偷懶了==。

         至于伺服器設計上的,挺麻煩。一些開源架構,恩,IBM developerWorks裡的一些文章都可以學習借鑒。

<a href="http://down.51cto.com/data/2360965" target="_blank">附件:http://down.51cto.com/data/2360965</a>

     本文轉自winorlose2000 51CTO部落格,原文連結:http://blog.51cto.com/vaero/921783,如需轉載請自行聯系原作者