四、 Message.java
定义的字符串消息。
- 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
- // 构造和解析方式详细参见附件工程了
- }
五、 ChatServerTest.java
服务器消息处理实现。
- public class ChatServerTest implements Observer, Runnable {
- private static final String BLANK = " ";
- /** 在线客户端信息 */
- private HashMap<InetSocketAddress, String> 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<InetSocketAddress, String>();
- break;
- case ChatServer.SEV_OFF:
- System.out.println("服务器关闭了");
- onLineMap = null;
- break;
- case ChatServer.CLT_CONNECT:
- // InetSocketAddress address = (InetSocketAddress) arg;
- break;
- case ChatServer.CLT_DISCONNECT:
- quit((InetSocketAddress) arg);
- break;
- case ChatServer.MSG_SEND:
- // System.out.println("通知:"
- // + ((String) arg).split(Message.SEPARATOR)[1]);
- break;
- case ChatServer.MSG_RECEIVE:
- Message msg = Message.getInstance();
- msg.create(server.getReceiveMessage());
- msg.setFromIp((InetSocketAddress) arg);
- handleMsg(msg); // 处理消息
- break;
- case ChatServer.ERROR:
- System.out.println("error : " + ((Exception) arg).getMessage());
- break;
- }
- }
- 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);
- break;
- case Message.MSG_4:
- System.out.println(onLineMap.get(msg.getFromIp()) + BLANK + "said"
- + BLANK + msg.getMsg());
- msg.setType(Message.MSG_6);
- server.send(msg.toString());
- break;
- case Message.MSG_7:
- quit(formIp);
- break;
- }
- }
- 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);
- Message msg = Message.getInstance();
- msg.setType(Message.MSG_8);
- msg.setFromIp(address);
- server.send(msg.toString());
- }
- }
- @Override
- 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();
- }
- }
六、 ChatClientTest.java
客户端消息处理实现。
- public class ChatClientTest implements Observer, Runnable {
- private static final String BLANK = " ";
- /** 在线客户端信息 */
- private HashMap<InetSocketAddress, String> onLineMap;
- private String name;
- private ChatClient client;
- public ChatClientTest(String name) {
- this.onLineMap = new HashMap<InetSocketAddress, String>();
- this.name = name;
- client = new ChatClient("192.168.1.107", 8899);
- // client = new ChatClient("127.0.0.1", 8899);
- client.addObserver(this);
- client.start();
- new Thread(this).start();
- }
- @Override
- public void update(Observable o, Object arg) {
- 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());
- break;
- case ChatClient.CLT_DISCONNECT:
- System.out.println("断开服务器连接");
- System.exit(1);
- break;
- case ChatClient.MSG_SEND:
- break;
- case ChatClient.MSG_RECEIVE:
- Message msg = Message.getInstance();
- msg.create((String) arg);
- handleMsg(msg); // 处理消息
- break;
- case ChatClient.ERROR:
- System.out.println("error : " + ((Exception) arg).getMessage());
- break;
- }
- }
- private void handleMsg(Message msg) {
- int type = msg.getType();
- switch (type) {
- case Message.MSG_2:
- System.out.println(msg.getMsg() + BLANK
- + msg.toIpString(msg.getFromIp()) + BLANK + "登录了");
- onLineMap.put(msg.getFromIp(), msg.getMsg());
- break;
- case Message.MSG_3:
- onLineMap = msg.getOnLineMap();
- System.out.println("连接上了服务器");
- System.out.println("/***在线成员***/");
- Iterator<Entry<InetSocketAddress, String>> it = onLineMap
- .entrySet().iterator();
- while (it.hasNext()) {
- Entry<InetSocketAddress, String> entry = it.next();
- InetSocketAddress address = entry.getKey();
- System.out.println(entry.getValue() + BLANK
- + address.getAddress().getHostAddress() + ":"
- + address.getPort());
- }
- System.out.println("/***在线成员***/");
- break;
- case Message.MSG_4:
- System.out.println("通知:" + msg.getMsg());
- break;
- case Message.MSG_6:
- System.out.println(onLineMap.get(msg.getFromIp()) + BLANK + "said"
- + BLANK + msg.getMsg());
- break;
- case Message.MSG_8:
- InetSocketAddress address = msg.getFromIp();
- System.out
- .println(onLineMap.get(address) + BLANK
- + Message.getInstance().toIpString(address) + BLANK
- + "退出了");
- onLineMap.remove(address);
- break;
- }
- }
- @Override
- 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("quit")) {
- client.send(Message.MSG_7 + "");
- client.close();
- break;
- } else {
- // 参见ChatServerTest注释
- inputLine = new String(inputLine.getBytes("gbk"), "utf-8");
- client.send(Message.MSG_4 + Message.SEPARATOR + 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 ChatClientTest("用户" + new Random().nextInt(100));
- }
- }
七、其他
客户端记录用的Map,消息就简单定义的字符串,指定某些IP发送消息没写。总之不影响主要功能的,能偷懒的都尽可能偷懒了==。
至于服务器设计上的,挺麻烦。一些开源框架,恩,IBM developerWorks里的一些文章都可以学习借鉴。