韩顺平QQ项目给离线用户发送信息

news/2025/3/15 22:13:13/

在线用户给离线用户发送消息

在下面代码中,仅仅展示私聊时,在线用户给离线用户发送消息,不考虑群发消息或者文件发送。

因为消息的接收者不在线,所以服务端线程集合里,不存在消息接收者的线程。故而这里会爆一个空指针异常

为了解决这个问题,我们就要在服务端线程里的私聊代码块中判断消息接收者的线程是否存在。

下面的是我修改之后的服务器线程关于私聊的代码块

if (message.getMesType().equals(MessageType.MESSAGE_COME_MES)) {System.out.println(message.getSender()+"发送给" + message.getGetter() + "的消息:"+message.getContent());//得到接收者的输出流,将得到的信息返回if (ManageClientThreads.getServerConnectClientThread(message.getGetter())==null){//假如用户不在线//把消息存放进一个集合里,等到用户登陆时判断集合是否有自己没有接收到的信息,有的话取出来NoOnlineUserMessage.hashMap.put(message.getGetter(),message);}else {ObjectOutputStream objectOutputStream = new ObjectOutputStream(ManageClientThreads.getServerConnectClientThread(message.getGetter()).getSocket().getOutputStream());objectOutputStream.writeObject(message);//加入客户不在线,可以保存到数据库,可以实现离线留言}}

大家可能已经注意到了,我将在线用户发送给离线用户的消息存放进了一个集合里面,之后离线用户上线时,可以通过这个集合来获取自己因为离线而没有收到的消息,我新开了一个类,专门存放这个集合。

集合的key是消息的接收者,也就是离线用户的id,value是消息本身

package QQServer.Service;import QQCommon.Message;import java.util.HashMap;public class NoOnlineUserMessage {public static HashMap<String, Message> hashMap=new HashMap<>();
}

以上就是在线用户给离线用户发送消息的全部了,接下来我将叙述离线用户如何获取集合里的消息

离线用户接收自己离线时的消息

我把这个功能放进了用户的二级菜单里面了

我的二级菜单

System.out.println("============网络通信系统二级菜单============");System.out.println("\t\t 1 显示在线用户列表");System.out.println("\t\t 2 群发消息");System.out.println("\t\t 3 私聊消息");System.out.println("\t\t 4 发送文件");System.out.println("\t\t 5 查看自己离线时没有收到的信息");System.out.println("\t\t 9 退出系统");System.out.println("请输入您的选择:~~~~");

之后在switch函数里的case新加一个判断:

                                case "5":System.out.println("查看自己离线时没有接收到的信息");messageClientService.LookMyNoLookMessage(userID);break;

我把这个LookMyNoLookMessage(String sender)方法写进了发送信息的服务类(MessageClientService)了

LookMyNoLookMessage(String sender):我们定义一个新的消息,我们需要设置消息的类型以及消息的发送者,发送给服务器端。这个消息的主要作用就是将消息的发送者与服务器端的集合的key进行比对,类似于小蝌蚪找妈妈

public void LookMyNoLookMessage(String sender){Message message = new Message();message.setSender(sender);message.setMesType(MessageType.MESSAGE_LOOK_MY_NO_LOOK);try {ObjectOutputStream objectOutputStream = new ObjectOutputStream(ManageClientConnectServerThread.getClientConnectServiceThread(message.getSender()).getSocket().getOutputStream());objectOutputStream.writeObject(message);} catch (IOException e) {e.printStackTrace();}}

需要注意的是,因为这是一个全新的方法,所以我在消息类型里面新定义了一个Type。

以下代码是我的MessageType,类型9就是我新定义的,一定注意,客户端与服务端的MessageType一定要保持一致

package QQCommon;public interface MessageType {//在接口里面定义常量,不同的常量代表不同的消息类型String MESSAGE_LOGIN_SUCCEED = "1";//登录成功String MESSAGE_LOGIN_FAIL="2";//登录失败String MESSAGE_COME_MES="3";//普通信息包String MESSAGE_GET_ONLINE_FRIEND="4";//要求返回用户列表String MESSAGE_RET_ONLINE_FRIEND="5";//返回在线用户列表String MESSAGE_CLIENT_EXIT="6";//客户端要求退出String MESSAGE_GROUP_CHAT="7";//群聊String MESSAGE_SEND_FILES="8";//发送文件String MESSAGE_LOOK_MY_NO_LOOK="9";//查看离线时没有接收到的信息
}

我们调用这个函数之后,服务器端会接收到一个消息,我们对消息的类型进行判断。

遍历集合,找到与发送者一样的key,得到发送者因为离线而没有收到的消息,之后得到发送者的输出流,输出流输出我们在集合找到的message,重新发送给客户端

if (message.getMesType().equals(MessageType.MESSAGE_LOOK_MY_NO_LOOK)){Iterator<String> iterator = NoOnlineUserMessage.hashMap.keySet().iterator();while (iterator.hasNext()) {String next = iterator.next().toString();if (next.equals(message.getSender())){//NoOnlineUserMessage.hashMap.get(next)//这个就是没有接收到的信息ObjectOutputStream objectOutputStream = new ObjectOutputStream(ManageClientThreads.getServerConnectClientThread(next).getSocket().getOutputStream());objectOutputStream.writeObject(NoOnlineUserMessage.hashMap.get(next));}}}

客户端进行接收,并把消息打印到输出台上。

if (message.getMesType().equals(MessageType.MESSAGE_LOOK_MY_NO_LOOK)){System.out.println("这是你离线时没有接收到的信息:");System.out.println("发送者:   " + message.getSender() + '\n' +"接收者:   " + message.getGetter() + '\n' +"发送时间:   " + message.getSendTime() + '\n' +"内容:   " + message.getContent() + '\n');}

代码到这里基本就已经完成了,看看效果吧!

程序效果

大家可以看到,这里只运行了一个客户,在线客户给离线客户发送信息

这是服务器端的情况,可以看到正常,没有报错

之后我们登录用户200,查看离线时自己错过的信息

效果比较理想。

总结

总体思路就是,在线用户给离线用户发送信息,离线用户暂时收不到,我们便把消息放到一个集合里面,之后等离线用户上线后,对服务器端进行示意,表示自己已经上线,就想办法从集合里重新取出自己的消息,之后发给自己。

PS:

我的第一篇博客,如果大家对于这个内容有任何不明白的地方,请私信我,我将尽我全力无偿向大家解答。


http://www.ppmy.cn/news/947683.html

相关文章

安卓实现qq离线图像变灰色或暗色效果

头像由彩色变灰色有两种实现方式&#xff1a; /** 方法1&#xff1a;* ColorMatrix类有一个内置的方法可用于改变饱和度。* 传入一个大于1的数字将增加饱和度&#xff0c;而传入一个0&#xff5e;1之间的数字会减少饱和度。0值将产生一幅灰度图像。*/ColorMatrix matrix new C…

QT之灰色头像(类似QQ离线头像)

QT之灰色头像(类似QQ离线头像) QT之灰色头像类似QQ离线头像 概要效果图上代码下代码结尾 概要 在讲正常图片转灰色图片之前&#xff0c;我们先来了解下灰度图。灰度图又称为灰阶图&#xff0c;任何颜色都由红、绿、蓝三原色组成&#xff0c;假如原来某点的颜色为RGB(R&#xf…

韩顺平老师QQ离线消息

1、Message 类&#xff0c;增加 Arraylise<Message>属性&#xff0c;MessageType 类增加离线消息类型 private ArrayList<Message> arrayList; String MESSAGE_OFFLINE "10";//离线消息类型 2、发送方用户正常发送消息 3、服务器判断接收方用户是否在…

若依vue -【 33 ~ 】

33 登录日志 系统管理 > 日志管理 > 登录日志 1 应用场景 统计用户的活跃度用户错误输入密码多少次 2 后台实现 &#xff08;1&#xff09;SysLoginController#login&#xff1a;登录 /*** 登录方法* * param loginBody 登录信息* return 结果*/PostMapping("/…

golang 日志库zap和日志切割实践

介绍 在许多Go语言项目中&#xff0c;我们需要一个好的日志记录器能够提供下面这些功能&#xff1a; 能够将事件记录到文件中&#xff0c;而不是应用程序控制台。 日志切割-能够根据文件大小、时间或间隔等来切割日志文件。 支持不同的日志级别。例如INFO&#xff0c;DEBUG&a…

万恶之源?

这是我第一次发布文章&#xff0c;我将分享Java后端的一些常用技术

来自鬼灭之刃迷的发表

炎柱母亲&#xff1a;知道你为什么刚生下来就比别人更强壮吗&#xff1f;那是因为上天要你用自己的天赋保护那些弱小之人。用自己的天赋欺负别人、中饱私囊。都是不允许的。 炎柱临死前&#xff1a;不管自己的懦弱和不中用&#xff0c;再怎么狠狠打击你。都要挺起胸膛&#xff…

鬼灭之刃中的人名儿

碳制郎的同期朋友&#xff0c;嘴平伊之助。 不知道是音译还是意译&#xff0c;这明明就是“嘴平一只猪”吗。 笑死&#xff0c;同时给翻译点个赞。