p2p|韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收

我这里只显示需要添加的代码,其余代码与韩老师写的一样。
这里用户1发短信给用户2
大体思路:1.在服务器接收用户1输入信息ObjectInputStream的时候有两个分支(if-else),
第一,如果在线程池里用户2不存在,就把输入信息保存在concurrentHashMap
第二,如果线程池里存在用户2,就把输入信息通过ObjectOutputStream.WriteObject发给客户端。
2.在服务器,用户2发送登录成功MessageType给客户端的时候,同时把用户1的信息也发出去,通过message.setContent()。
建议自己在想一下,因为很简单,具体代码如下:
1.设定属性.private static ConcurrentHashMap>ofLineDb = new ConcurrentHashMap<>();
2.写方法用来保存内容
public static void dbmessage(String userId,Message message1){
if (!ManageClientThread.getHm().containsKey(userId)){
ArrayList messages1 = new 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){ ArrayList messages = 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; //连接到服务端的用户idpublic 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 { //传递给需要收到的用户idServerConnectClientThread 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 staticvoid 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,发短信
p2p|韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收
文章图片

登入200发短信p2p|韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收
文章图片

p2p|韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收
文章图片





【p2p|韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收】

    推荐阅读