韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收
我这里只显示需要添加的代码,其余代码与韩老师写的一样。
这里用户1发短信给用户2
大体思路:1.在服务器接收用户1输入信息ObjectInputStream的时候有两个分支(if-else),
第一,如果在线程池里用户2不存在,就把输入信息保存在concurrentHashMap
第二,如果线程池里存在用户2,就把输入信息通过ObjectOutputStream.WriteObject发给客户端。
2.在服务器,用户2发送登录成功MessageType给客户端的时候,同时把用户1的信息也发出去,通过message.setContent()。
建议自己在想一下,因为很简单,具体代码如下:
1.设定属性.private static ConcurrentHashMap<String, ArrayList<Message>>ofLineDb = new ConcurrentHashMap<>();
2.写方法用来保存内容
public static void dbmessage(String userId,Message message1){
if (!ManageClientThread.getHm().containsKey(userId)){
ArrayList<Message> 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找到socketServerConnectClientThread 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<Message> messages = ofLineDb.get(o1.getUserId());Iterator<Message> 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;}@Overridepublic 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<String, ServerConnectClientThread> hm = ManageClientThread.getHm();Iterator<String> iterator = hm.keySet().iterator();while (iterator.hasNext()) {String next = iterator.next();//取出在线用户idif (!(next.equals(o1.getSender()))){//进行转发messageObjectOutputStream 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<String,User> validUsers = new HashMap<>();private static ConcurrentHashMap<String, ArrayList<Message>>ofLineDb = new ConcurrentHashMap<>();public static ConcurrentHashMap<String, ArrayList<Message>> getOfLineDb() {return ofLineDb;}public static void setOfLineDb(ConcurrentHashMap<String, ArrayList<Message>> 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<Message> 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) {//监听是循环的一直监听的,当合某个客户端建立链接后,会继续监听,如果没有客户端服务器会阻塞在这里//因此whileSocket 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<Message> messages = ofLineDb.get(o1.getUserId());Iterator<Message> 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();//把该线程对象,放入到一个集合中,进行管理,//写DBManageClientThread.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,说明服务器端不在监听,因此关闭ServerSockettry {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){//构建messageMessage 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,发短信
登入200发短信
韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收相关推荐
- 尚硅谷Java数据结构和java算法,韩顺平数据结构和算法课后作业01
尚硅谷Java数据结构和java算法,韩顺平数据结构和算法课后作业第一题 要求: 1)在前面的基础上,将稀疏数组保存到磁盘上,比如map.data 2) 恢复原来的数组时,读取map.data进行恢复 ...
- 适合有编程基础的人看的《韩顺平零基础30天学java》笔记(P104~P129)
写在最前边: 研究生一枚,为后端实习和未来工作打基础.无意间发现韩顺平老师的课程,细心细致,讲课和吴恩达老师一样,都是保姆式讲解,各种基础知识都会补充,爱了. 韩顺平老师课程地址:https://ww ...
- 观韩顺平的《0基础30天学会Java》后感
万丈高楼平地起,在韩老师的带领下你的筑基期肯定很强,日后成仙指日可待. 开门先说重点:一定要加韩老师微信要资料!一定要加韩老师微信要资料!一定要加韩老师微信要资料!,重要的事情说三遍,千万不要去官网下 ...
- 韩顺平集合课后作业Homework06.java探讨
看了韩顺平老师的视频获益匪浅,但是这里有点不太懂,希望会的大神能帮助解答一下.第二次输出前的:set.add(new Person(1001,"CC"));为啥能add进HashS ...
- 韩顺平Java:qq项目离线发送接收消息/文件扩展
思路:1.在服务端创建一个ConcurrentHashMap线程安全的集合用来存储离线用户的消息和文件,为了实现每个用户可以保存多条离线消息,我们在键值对value中采用ArrayList来保存多条m ...
- servletjsp入门.....韩顺平笔记
u 背景知识介绍 J2EE的13种技术 java->servlet->jsp [技术总是有一个演变过程] zip粘贴到word设置 u 回顾一下我们现有的技术 java 基础(面向对象,集 ...
- 韩顺平的php东方航空_韩顺平php视频教程
韩顺平php从入门到精通视频教程是由知名的讲师韩顺平制作讲解的一套php基础入门教程,也是自学PHP必备的一系列教程.包含了php开山篇.html介绍.html运行原理.网上支付平台开发实例.XML编 ...
- 韩顺平主讲PHP从入门到精通掌握网站核心技术
本视频教程为传智播客讲师韩顺平讲解 视频目录如下: 下载地址:百度网盘 0讲 PHP开山篇 1讲 html介绍 html运行原理① 2讲 html运行原理② html文件基本结构 html元素和属性 ...
- Java基础易忘重点内容笔记【附B站韩顺平老师课程链接】
B站课程链接:https://www.bilibili.com/video/BV1fh411y7R8?spm_id_from=333.999.0.0 1. 文档注释 用于对Java方法的注释,可据此生 ...
最新文章
- php手机底部菜单,html5手机web页面底部菜单
- 【Linux】一步一步学Linux——split命令(59)
- github 如何设置项目的语言显示
- 【OCR技术系列之五】自然场景文本检测技术综述(CTPN, SegLink, EAST)
- python3 windows console 输出乱码问题
- 计算机的关机键,怎么让电脑按关机键后不关机?让电脑主机上关机键失效的方法...
- [vb]SendMessageA函数
- ubuntu jdk tomcat mysql_linux-ubuntu tomcat jdk 及 mysql 安装配置
- 用word怎么做c语言框图作业,在Word中绘制简单C语言流程图精.docx
- VB程序设计教程(第四版) 龚沛曾
- 如何使用工时表软件跟踪时间和成本?
- 【建议收藏】手把手教你画一个项目的技术架构图
- 163邮箱如何注册呢?
- python爬取网课答案_高校邦网络数据采集与Python爬虫【带实验】网课答案
- ASP.NET网站部署详细步骤
- 04_python爬虫爬取超星回放
- javaweb_util_excel模板横向纵向循环
- opencv实现matlab的median()函数
- 检测ip是否为中国php,PHP判断IP是中国IP还是外国IP
- 有趣且重要的JS知识合集(18)浏览器实现前端录音功能
热门文章
- DBeaver安装完成使用时下载驱动报错的问题--网络原因
- 自尊宣言—个人力量的源泉
- HuaPu在学:机器学习——sklearn【决策树】
- 键盘1左边的符号叫什么 mysql_~!#$%^*这些符号怎么读? 当然是用英语(键盘特殊符号小结)...
- 除非……否则……在命题公式中的翻译(符号化)
- 湖北松滋历史上十二大李氏家族
- 阿里云视频点播-记录
- iOS URLWithString返回为空nil的解决方案
- Python向上取整和向下取整
- 华三路由追踪命令 tracert详解