我这里只显示需要添加的代码,其余代码与韩老师写的一样。
这里用户1发短信给用户2
大体思路:1.在服务器接收用户1输入信息ObjectInputStream的时候有两个分支(if-else),
第一,如果在线程池里用户2不存在,就把输入信息保存在concurrentHashMap
第二,如果线程池里存在用户2,就把输入信息通过ObjectOutputStream.WriteObject发给客户端。
2.在服务器,用户2发送登录成功MessageType给客户端的时候,同时把用户1的信息也发出去,通过message.setContent()。
建议自己在想一下,因为很简单,具体代码如下:
1.设定属性.private static ConcurrentHashMap
2.写方法用来保存内容
public static void dbmessage(String userId,Message message1){
if (!ManageClientThread.getHm().containsKey(userId)){
ArrayList
messages1.add(message1); ofLineDb.put(userId,messages1);
}
3.服务器对收到的信息进行分流 else if (o1.getMesType().equals(MessageType.MESSAGE_COMM_MES.getNum())){ //把客户端私聊的内容保存在dbmessage方法里的ConcurrentHashMap里 if (!ManageClientThread.getHm().containsKey(o1.getGetter())) { o1.setContent("\n"+o1.getSender()+"发消息说"+o1.getContent()); QQserver.dbmessage(o1.getGetter(), o1); } //传递给客户端,通过需要收到的用户id找到socket ServerConnectClientThread getserverconnectclietnthread = ManageClientThread.getserverconnectclietnthread(o1.getGetter()); ObjectOutputStream objectOutputStream = new ObjectOutputStream(getserverconnectclietnthread.getSocket().getOutputStream()); objectOutputStream.writeObject(o1); }
4.在服务器,当用户2登入时,从数组里取出用户1的信息打包过去。
if (ofLineDb.get(o1.getUserId())!=null){ ArrayListmessages = ofLineDb.get(o1.getUserId()); Iterator iterator = messages.iterator(); while (iterator.hasNext()) { Message next = iterator.next(); message.setContent(next.getContent()); } }
5.客户端里输出
if (ManageClientConnectiServerThread.getccst(message.getGetter())==null){System.out.println(message.getGetter()+"用户已经离线");}else { System.out.println(senderId+"对"+getterId+"说"+content);}
服务器端的:
public class ServerConnectClientThread extends Thread{
private Socket socket;
private String userId;//连接到服务端的用户id
public ServerConnectClientThread(Socket socket, String userId) {
this.socket = socket;
this.userId = userId;
}
@Override
public void run() {//这里线程处于rum的状态,可以发送/接送消息
while(true){
System.out.println("服务端和客户端"+userId+"保持通信,读取数据...");
try {
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Object o = objectInputStream.readObject();
Message o1 = (Message) o;
// 后面会使用message
// 根据message的类型,做相应的业务处理
if (o1.getMesType().equals(MessageType.MESSAGE_GET_ONLINEFRIEND.getNum())){
//客户端要在先用户列表
/*
在线用户列表形式100 200
*/
System.out.println(o1.getSender()+"要在线用户列表");
String onlineUser = ManageClientThread.getOnlineUser();
//返回message
//构建一个message对象,返回给客户端
Message message = new Message();
message.setMesType(MessageType.MESSAGE_RET_ONLINEFRIEND.getNum());
message.setContent(onlineUser);
message.setGetter(message.getSender());
//返回给客户端
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(message);
} else if (o1.getMesType().equals(MessageType.MESSAGE_CLIENT_EXIT.getNum())) {//如果客户端退出把socket退出
System.out.println(o1.getSender()+"退出");
//将这个客户端对应线程,从集合中删除
ManageClientThread.removeServerConnectClientThread(o1.getSender());
socket.close();//关闭链接
//退出线程
break;
} else if (o1.getMesType().equals(MessageType.MESSAGE_COMM_MES.getNum())){
//把客户端私聊的内容保存在dbmessage方法里的ConcurrentHashMap里
if (!ManageClientThread.getHm().containsKey(o1.getGetter())) {
o1.setContent("\n"+o1.getSender()+"发消息说"+o1.getContent());
QQserver.dbmessage(o1.getGetter(), o1);
}else {
//传递给需要收到的用户id
ServerConnectClientThread getserverconnectclietnthread = ManageClientThread.getserverconnectclietnthread(o1.getGetter());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(getserverconnectclietnthread.getSocket().getOutputStream());
objectOutputStream.writeObject(o1);
}
//如果,提示客户不在线,通过保存到数据库达到离线留言
}else if (o1.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES.getNum())){
HashMap hm = ManageClientThread.getHm();
Iterator iterator = hm.keySet().iterator();
while (iterator.hasNext()) {
String next = iterator.next();
//取出在线用户id
if (!(next.equals(o1.getSender()))){
//进行转发message
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(hm.get(next).getSocket().getOutputStream());
objectOutputStream.writeObject(o1);
}
} hm.remove(o1.getSender());
}else if (o1.getMesType().equals(MessageType.FILE_TO_ONE_MES.getNum())){
ServerConnectClientThread getserverconnectclietnthread =
ManageClientThread.getserverconnectclietnthread(o1.getGetter());
Socket socket = getserverconnectclietnthread.getSocket();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(o1);
}
else {
System.out.println("其他类型的message,暂时不处理");
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
}
public class QQserver {
//ConcurrentHashMap,线程安全的HashMap,多线程下是阿暖的
private ServerSocket ss =null;
//创建一个集合,存放多个用户,如果是这些用户登入就认为是合法的
private static HashMap validUsers = new HashMap<>();
private static ConcurrentHashMap>ofLineDb = new ConcurrentHashMap<>();
public static ConcurrentHashMap> getOfLineDb() {
return ofLineDb;
}
public static void setOfLineDb(ConcurrentHashMap> ofLineDb) {
QQserver.ofLineDb = ofLineDb;
}
static {//在静态代码块,初始化validUsers
//
validUsers.put("100",new User("100","123456"));
validUsers.put("200",new User("200","123456"));
validUsers.put("300",new User("300","123456"));
validUsers.put("至尊宝",new User("至尊宝","123456"));
validUsers.put("铺地老祖",new User("菩提老祖","123456"));
}
public static void dbmessage(String userId,Message message1){
if (!ManageClientThread.getHm().containsKey(userId)){
ArrayList messages1 = new ArrayList<>();
messages1.add(message1);
ofLineDb.put(userId,messages1);
}
}
private boolean checkUser(String userId,String passwd){
System.out.println("准备登入");
User user = validUsers.get(userId);
if (user==null){//说明userId没有存在validUsers的key中
return false;
}if (!user.getPasswd().equals(passwd)){//userId正确,但是密码错误
return false;
}
return true;
}
public QQserver() {
System.out.println("服务端在9999端口监听。。。");
try {
//启动推送新闻的线程
new Thread(new SendNewsToALLService()).start();
ss = new ServerSocket(9999);
while(true) {//监听是循环的一直监听的,当合某个客户端建立链接后,会继续监听,如果没有客户端服务器会阻塞在这里
//因此while
Socket accept = ss.accept();//如果没有客户端链接,就会阻塞
//得到socket关联的对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(accept.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(accept.getOutputStream());
Object o = objectInputStream.readObject();
//得到socket冠梁的对象输出流
User o1 = (User) o;
//创建一个Message对象,准备回复客户端
Message message = new Message();
//验证
if (checkUser(o1.getUserId(),o1.getPasswd())){//登录通过
//登录成功
message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED.getNum());
//将Message对象回复
//封装私聊内容发送给客户端
if (ofLineDb.get(o1.getUserId())!=null){
ArrayList messages = ofLineDb.get(o1.getUserId());
Iterator iterator = messages.iterator();
while (iterator.hasNext()) {
Message next = iterator.next();
message.setContent(next.getContent());
}
}
objectOutputStream.writeObject(message);
//创建一个线程,和客户端进行链接
ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(accept, o1.getUserId());
serverConnectClientThread.start();
//把该线程对象,放入到一个集合中,进行管理,
//写DB
ManageClientThread.addClentThread(o1.getUserId(), serverConnectClientThread);
}else {
//登录失败]
System.out.println("用户id="+ o1.getUserId()+"验证失败");
message.setMesType(MessageType.MESSAGE_LOGIN_FAIL.getNum());
objectOutputStream.writeObject(message);
accept.close();
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
//如果服务器退出了while,说明服务器端不在监听,因此关闭ServerSocket
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端的:
public class MessageClientService {
/**
*
* @param content 内容
* @param senderId 发送用户id
* @param getterId 接收用户id
*/
public static void sendMessageToOne(String content,String senderId,String getterId){
//构建message
Message message = new Message();
message.setSender(senderId);
message.setGetter(getterId);
message.setContent(content);
message.setMesType(MessageType.MESSAGE_COMM_MES.getNum());//设置消息类型
message.setSendTime(new Date().toString());//发送时间设置到message对象
if (ManageClientConnectiServerThread.getccst(message.getGetter())==null){System.out.println(message.getGetter()+"用户已经离线");}else
{ System.out.println(senderId+"对"+getterId+"说"+content);}
//发送给服务端
try {
ClientConnectServerThread getccst = ManageClientConnectiServerThread.getccst(senderId);
Socket socket = getccst.getSocket();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void sendMessageToAll(String content,String senderId){
Message message = new Message();
message.setSender(senderId);
message.setContent(content);
message.setMesType(MessageType.MESSAGE_TO_ALL_MES.getNum());//设置消息类型群发
message.setSendTime(new Date().toString());//发送时间设置到message对象
System.out.println(senderId+"对大家说"+content);
//发送给服务端
try {
ClientConnectServerThread getccst = ManageClientConnectiServerThread.getccst(senderId);
Socket socket = getccst.getSocket();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
效果:
登入100,发短信