首先定义一个Msg类 类中包含 发送者 接收者 及消息
public class Msg {
private String sender;
private String receiver;
private String msg;
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getReceiver() {
return receiver;
}
public void setReceiver(String receiver) {
this.receiver = receiver;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
然后定义一个 全局Map 来存储在线人数
public class OnlineMap {
private final static Map<String, Object> onlineMap = Maps.newHashMap();
public static Object get(String key) {
return onlineMap.get(key);
}
public static void put(String key, Object obj) {
onlineMap.put(key, obj);
}
public static int getCount() {
return onlineMap.size();
}
public static void remove(String key) {
onlineMap.remove(key);
}
public static String getOnlineInfo() {
Iterator iterator = onlineMap.keySet().iterator();
StringBuilder builder = new StringBuilder();
while (iterator.hasNext()) {
builder.append(iterator.next()).append(",");
}
return builder.toString();
}
}
接着定义 服务端
public class TalkServer {
//用户集合
private static ArrayList<Socket> list = new ArrayList<Socket>();
public static void main(String[] args) {
//上线用户
Socket s = null;
//用户
String ip = null;
String name = null;
try {
//构建服务器对象
ServerSocket ss = new ServerSocket(1234);
//构建 用户集合
list = new ArrayList<Socket>();
System.out.println("服务器准备就绪 ...");
//循环监听
while(true){
//上线用户
s = ss.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
//上线的人都添加到 集合中
list.add(s);
name = reader.readLine();
OnlineMap.put(name, s);
System.out.println(OnlineMap.getOnlineInfo());
//获取 Socket IP
ip = s.getInetAddress().getHostAddress();
System.err.println( ip + name +" 用户上线了 , 当前在线用户为: " + list.size() + "人 !"+OnlineMap.getOnlineInfo() );
//构建 发送信息线程
M2MSend send = new M2MSend(s, name);
send.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static ArrayList<Socket> getList() {
return list;
}
public static void setList(ArrayList<Socket> list) {
TalkServer.list = list;
}
}
服务端中包含一个 转发消息的 线程类M2MSend
public class M2MSend extends Thread{
//用户集合
private ArrayList<Socket> list = TalkServer.getList();
//当前用户
private Socket s;
private String name;
public M2MSend(Socket s, String name){
this.s = s;
this.name = name;
}
public void run(){
//获取该用户 IP
String ip = s.getInetAddress().getHostAddress();
try {
//读取用户信息
BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
ObjectMapper mapper = JsonUtil.getMapper();
//不断的读取写出数据
while(true){
//接收数据
String info = null;
//如果读取信息不为空
if((info=reader.readLine()) != null){
Msg msg = mapper.readValue(info, Msg.class);
Socket ss = (Socket) OnlineMap.get(msg.getReceiver());
//遍历所有的在线用户,并且把信息发送过去
if (ss != null) {
PrintWriter pw = new PrintWriter(ss.getOutputStream());
// msg.setMsg(ip + " "+ msg.getSender() +" 说: " + msg.getMsg());
//写入信息
pw.println(mapper.writeValueAsString(msg));
pw.flush();
} else {
for(Socket sss : list){
//获取对象的输出流
PrintWriter pw;
pw = new PrintWriter(sss.getOutputStream());
// msg.setMsg(ip + " "+ msg.getSender() +" 说: " + msg.getMsg());
//写入信息
pw.println(mapper.writeValueAsString(msg));
pw.flush();
}
}
}
}
} catch (IOException e1) {
//用户下线
list.remove(s);
OnlineMap.remove(name);
System.err.println(ip + name +" 已下线 , 当前在线人数为: " + list.size() + " 人 !"+OnlineMap.getOnlineInfo());
}
}
}
然后定义客户端
public class TalkClient {
public static void main(String[] args) {
try {
//先从键盘接收信息
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入昵称:");
String sender = br.readLine();
//构建客户端对象
Socket s = new Socket("localhost", 1234);
//写入到 Socket 中
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.println(sender);
pw.flush();
ObjectMapper mapper = JsonUtil.getMapper();
//启动线程
M2MReceive receive = new M2MReceive(s);
receive.start();
while (true) {
Msg msg = new Msg();
System.out.println("请输入接收人:");
String receiver = br.readLine();
System.out.println("请输入发送的消息:");
String message = br.readLine();
msg.setSender(sender);
msg.setReceiver(receiver);
msg.setMsg(message);
if (msg != null) {
System.out.println("自己说:" + message);
//写出
pw.println(mapper.writeValueAsString(msg));
pw.flush();
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端中包含一个 接收服务端消息的线程类M2MReceive
public class M2MReceive extends Thread{
private Socket s;
public M2MReceive(Socket s){
this.s = s;
}
public void run(){
try {
String ip = s.getInetAddress().getHostAddress();
//构建输入流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ObjectMapper mapper = JsonUtil.getMapper();
//不断的接收信息
while(true){
String info = null;
//接收信息
if((info=br.readLine()) != null){
System.out.println(info);
Msg msg = mapper.readValue(info, Msg.class);
System.out.println(ip + " "+ msg.getSender() +" 说: " + msg.getMsg());
System.out.println("请输入接收人:");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行说明
首先 运行server main方法 客户端登陆后会显示登陆人数 及 登陆人昵称列表
其次运行 client main方法 然后 客户端 会让在控制台输入昵称 该昵称为客户端的标识 然后会询问你 要发送给哪个昵称 然后输入消息
就可以 在对应昵称的客户端中看到发送的消息了
该例子用到了 apache的 jackson 和 guava的 Maps 需下载引入