天天看点

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,如需转载请自行联系原作者