网络多线程开发小项目--QQ登陆聊天功能(服务端推送新闻、离线留言和文件)
9.1.5、QQ登陆聊天功能(服务端推送新闻、离线留言和文件)
9.1.5.1、服务端推送新闻
1、需求分析

2、思路分析

3、代码实现
QQServer:
1)cn.com.agree.qqserver.service.SendNewsToAllClient
package cn.com.agree.qqserver.service;import cn.com.agree.qqcommon.Message;
import cn.com.agree.qqcommon.MessageType;
import cn.com.agree.stream.MyObjectOutputStream;
import cn.com.agree.util.Utility;
import lombok.extern.slf4j.Slf4j;import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;/*** @version 1.0* @ClassName SendNewsToAll* @Description TODO 类描述* @date 2024/1/12 11:37 上午**/
@Slf4j
public class SendNewsToAllClient implements Runnable {@Overridepublic void run() {while (true) {//构建消息对象Message message = new Message();message.setSender("服务器");message.setMsgType(MessageType.MESSAGE_ONLINEAll_MS);Scanner scanner = new Scanner(System.in);log.debug("请输入要推送的服务器消息(输入exit退出):");String news = scanner.next();if("exit".equals(news)){log.debug("服务器推送线程已退出");break;}message.setContent(news);message.setSendTime(new Date().toString());log.debug(message.getSender()+" 对大家说: "+message.getContent());//遍历服务端所有的用户id得到对应的线程socket转发给对应的客户端Map<String, ServerConnectClient> hm = ManageServerConnectClient.getHm();Iterator<String> iterator = hm.keySet().iterator();while (iterator.hasNext()) {String userId = iterator.next().toString();try {ObjectOutputStream oos = new MyObjectOutputStream(ManageServerConnectClient.getServerConnectClient(userId).getSocket().getOutputStream());oos.writeObject(message);} catch (IOException e) {e.printStackTrace();}}}}
}
2)cn.com.agree.qqserver.service.qqServer
while (true) {socket = serverSocket.accept();//获取来自客户端发送过来到用户对象log.debug("socket Client连接成功");new Thread(new SendNewsToAllClient()).start();ObjectInputStream bis = new MyObjectInputStream(socket.getInputStream());User user = (User) bis.readObject();//获取输出流对象写入返回给客户端的消息ObjectOutputStream oos = new MyObjectOutputStream(socket.getOutputStream());og.debug("user:{}",user);Message message = new Message();...
}
4、运行效果




9.1.5.2、离线留言和文件
1、需求分析

2、思路分析

3.1、代码实现(发送离线消息)
1)cn.com.agree.qqserver.service.ManageServerConnectClient
private static Map<String, List<Message>> notOnlineMessages = new ConcurrentHashMap<>();public static void addNotOnlineMessage(String getterId, List<Message> messages){notOnlineMessages.put(getterId, messages);}public static List<Message> getNotOnlineMessage(String getterId) {return notOnlineMessages.get(getterId);}
2)cn.com.agree.qqserver.service.ServerConnectClient
case MessageType.MESSAGE_COMM_MS:log.debug("message:{}", message);log.debug(message.getSender() + " 对 " + message.getGetter() + " 说: " + message.getContent());ServerConnectClient connectClient = ManageServerConnectClient.getServerConnectClient(message.getGetter());if(connectClient==null){//做离线消息处理,将数据保存到数据库(这里保存到Map中)if(ManageServerConnectClient.getNotOnlineMessage(message.getGetter())==null){List<Message> messages = new ArrayList<>();messages.add(message); ManageServerConnectClient.addNotOnlineMessage(message.getGetter(),messages);}else{ ManageServerConnectClient.getNotOnlineMessage(message.getGetter()).add(message);}}else {//转发消息ObjectOutputStream oos2 = new MyObjectOutputStream(connectClient.getSocket().getOutputStream());oos2.writeObject(message);//如果用户不在线,可以保存到数据库做离线转发}break;
3) cn.com.agree.qqserver.service.qqServer
//去服务端查询是否有来自他的消息,有的话转发给对应的用户List<Message> notOnlineMessage = ManageServerConnectClient.getNotOnlineMessage(user.getUserId());if(notOnlineMessage!=null&¬OnlineMessage.size()>0){for (Message message1 : notOnlineMessage) {ObjectOutputStream oos2 = new MyObjectOutputStream(socket.getOutputStream());oos2.writeObject(message1);}}
4.1、效果演示


上线后收到消息

3.2、代码实现(发送离线文件)
case MessageType.MESSAGE_FILE_MESSAGE://log.debug("message:{}", message);log.debug(message.getSender()+" 给 "+message.getGetter()+" 发送了 "+message.getSrc()+" 到我的电脑的 "+message.getDesc()+" 路径");ServerConnectClient serverConnectClient = ManageServerConnectClient.getServerConnectClient(message.getGetter());if(serverConnectClient==null){//做离线消息处理,将数据保存到数据库(这里保存到Map中)if(ManageServerConnectClient.getNotOnlineMessage(message.getGetter())==null){List<Message> messages = new ArrayList<>();messages.add(message);ManageServerConnectClient.addNotOnlineMessage(message.getGetter(),messages);}else{ManageServerConnectClient.getNotOnlineMessage(message.getGetter()).add(message);}}else {//进行转发给客户端ObjectOutputStream oos4= new MyObjectOutputStream(serverConnectClient.socket.getOutputStream());oos4.writeObject(message);}break;
4.2、效果展示


300上线后成功接收

相关文章:
网络多线程开发小项目--QQ登陆聊天功能(服务端推送新闻、离线留言和文件)
9.1.5、QQ登陆聊天功能(服务端推送新闻、离线留言和文件) 9.1.5.1、服务端推送新闻 1、需求分析 2、思路分析 3、代码实现 QQServer: 1)cn.com.agree.qqserver.service.SendNewsToAllClient package cn.com.agree.qqserver.s…...
Jtti:有哪些方法可以提升Tomcat的性能?
提升 Tomcat 性能是确保 Web 应用程序快速响应并能够处理高并发请求的关键任务。以下是一些提升 Tomcat 性能的常见方法: 1. 调整JVM参数: a. 内存分配: 增加 JVM 的堆内存(Heap Memory)以提高应用程序的内存容量。使用 -Xmx 和 -Xms 参数设置…...
LeetCode 2085. 统计出现过一次的公共字符串
目录 一、题目 1、题目描述 2、接口描述 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 C代码 Python3代码 一、题目 1、题目描述 给你两个字符串数组 words1 和 words2 ,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。 2…...
130基于MATLAB并结合IBD算法的盲迭代反卷积法进行图像复原
基于MATLAB并结合IBD算法的盲迭代反卷积法进行图像复原 ,输出复原前后图像,PSF频谱结果。程序已调通,可直接运行。 130 matlab盲迭代反卷积IBD (xiaohongshu.com)...
Flying HTML生成PDF添加水印
HTML转PDF并添加水印 <!-- 用于生成PDF --> <dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.20</version> </dependency>import java.io.File; import jav…...
MySQL 8.0 InnoDB Tablespaces之Temporary Tablespaces(临时表空间)
文章目录 MySQL 8.0 InnoDB Tablespaces之Temporary Tablespaces(临时表空间)会话临时表空间会话临时表空间的磁盘分配和回收会话临时表空间的创建创建临时表和查看临时表信息会话临时表空间相关的设置参数innodb_temp_tablespaces_dir 全局临时表空间查…...
轴承滚珠故障的理论推导与计算(修订中...)
1.缘起 轴承故障故障位置在高频,如果不即时处理,恶化后,滚珠会有单颗故障迅速恶化到多颗,如果此时电机承载较大负载,轴承的恶化,会牵连到相关的动力轴。是一个不可不进行监测的项目。 2.频谱特征 轴承的…...
NVMe系统内存结构 - PRP与PRP List
NVMe系统内存结构 - PRP与PRP List 1 为什么需要PRP2 PRP3 PRP List4 PRP寻址算法4.1 仅PRP1指向数据4.2 PRP1指向数据,PRP2指向数据4.3 PRP1指向数据,PRP2指向PRP List 本文属于《 NVMe协议基础系列教程》之一,欢迎查看其它文章。 1 为什么…...
系列二、Spring Security中的核心类
一、Spring Security中的核心类 1.1、自动配置类 UserDetailsServiceAutoConfiguration 1.2、密码加密器 1.2.1、概述 Spring Security 提供了多种密码加密方案,官方推荐使用 BCryptPasswordEncoder,BCryptPasswordEncoder 使用 BCrypt 强哈希函数&a…...
基于多反应堆的高并发服务器【C/C++/Reactor】(中)HttpRequest 提取请求行、解析请求行和优化 以及解析请求头并存储
### 知识点1:读取网络数据 客户端发送给服务器的通信数据通过封装的bufferSocketRead函数读取读取的数据存储在struct Buffer结构体实例中,可将该实例作为参数传递给解析函数 回顾Buffer.c中的bufferSocketRead函数 // 写内存 2.接收套接字数据 int b…...
数据结构-测试1
一、判断题 1.队列中允许插入的一端叫队头,允许删除的一端叫队尾(F) 队列中允许删除的一端叫队头(front),允许插入的一端叫队尾(rear) 2. 完全二叉树中,若一个结点没有左孩子&#…...
【设计模式】01-前言
23 Design Patterns implemented by C. 从本文开始,一系列的文章将揭开设计模式的神秘面纱。本篇博文是参考了《设计模式-可复用面向对象软件的基础》这本书,由于该书的引言 写的太好了,所以本文基本是对原书的摘抄。 0.前言 评估一个面向对…...
SpringBoot源码分析
一:简介 由Pivotal团队提供的全新框架其设计目的是用来简化新Spring应用的初始搭建以及开发过程使用了特定的方式来进行配置快速应用开发领域 二:运行原理以及特点 运行原理: SpringBoot为我们做的自动配置,确实方便快捷&#…...
约数个数和约数之和算法总结
知识概览 约数个数 基于算数基本定理,假设N分解质因数的结果为 可得对于N的任何一个约数d,有 因为N的每一个约数和~的一种选法是一一对应的,根据乘法原理可得, 一个数的约数个数为 约数之和 一个数的约数之和公式为 多项式乘积的…...
数据结构-怀化学院期末题(322)
图的深度优先搜索 题目描述: 图的深度优先搜索类似于树的先根遍历,是树的先根遍历的推广。即从某个结点开始,先访问该结点,然后深度访问该结点的第一棵子树,依次为第二顶子树。如此进行下去,直到所有的结点…...
小手也能用的高性能鼠标,自定义空间还挺高,雷柏VT9Pro mini上手
今年搭载PAW3395传感器的电竞鼠标很受欢迎,雷柏就出了不少型号,满足各种喜好的玩家选择,像是近期新出的搭载3395高定版的VT9Pro和VT9Pro mini,就在轻量化的基础上,满足了各种手型的玩家的使用需要,而且价格…...
CDN加速原理详解
一、CDN加速是什么意思 CDN是Content Delivery Network)英文首字母的缩写,中文翻译为内容分发网络,由于CDN是为加快网络访问速度而被优化的网络覆盖层,因此被形象地称为”网络加速器”,即CDN加速。CDN加速是通过将网站…...
sqlachemy orm create or delete table
sqlacehmy one to one ------detial to descript 关于uselist的使用。如果你使用orm直接创建表关系,实际上在数据库中是可以创建成多对多的关系,如果加上uselistFalse 你会发现你的orm只能查询出来一个,如果不要这个参数orm查询的就是多个,一对多的…...
科普小米手机、华为手机、红米手机、oppo手机、vivo手机、荣耀手机、一加手机、realme手机如何设置充电提示音
用空空鱼就可以设置,上面还有很多提示音素材还可以设置满电和低电提醒...
zookeeper应用场景之分布式的ID生成器
1. 分布式ID生成器的使用场景 在分布式系统中,分布式ID生成器的使用场景非常之多: 大量的数据记录,需要分布式ID。大量的系统消息,需要分布式ID。大量的请求日志,如restful的操作记录,需要唯一标识&#x…...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...
