<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<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;
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<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();
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<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("通知:" + 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,如需转载请自行联系原作者