day03-2无异常退出
多用户即时通讯系统03
4.编码实现02
4.3功能实现-无异常退出系统
4.3.1思路分析

上述代码运行时,在客户端选择退出系统的时候,可以发现程序并没有停止运行,原因是:
退出时,程序将循环标志loop设为false,退出了内层循环,而外层循环因为也用了loop来作为循环条件,外层循环也同样退出。此时在客户端 类QQView中的主线程已经结束,但是在循环过程中,因为与服务端连接而产生的线程并没有结束,整个进程也就没有结束,因此程序仍在运行中。
解决方法:
客户端:在main线程中调用方法,给服务端发送一个退出系统的message对象,然后调用System.exit(0)指令,正常退出。这样整个进程就可以关闭。
服务器端:在服务器这边,接收到一个退出系统的message对象后,把这个客户端对应的线程所持有的socket关闭,然后退出该线程

4.3.2代码实现
1.客户端:
1.修改:UserClientService类
在该类中增加logout()方法
//编写方法,退出客户端,并给服务器端发送一个退出系统的message对象
public void logout(){
    Message message = new Message();
    message.setMesType(MessageType.MESSAGE_CLIENT_EXIT);
    message.setSender(u.getUserId());//一定要指定是那个客户端,服务端要根据这个userId移除集合中的线程
    //发送message
    try {
        //从管理线程的集合里面,通过userId,得到这个线程对象
        ClientConnectServerThread clientConnectServerThread =
                ManageClientConnectServerThread.getClientConnectServerThread(u.getUserId());
        //通过这个线程中获取关联的socket
        Socket socket = clientConnectServerThread.getSocket();
        //得到当前线程的Socket对应的ObjectOutputStream对象
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        oos.writeObject(message);
        System.out.println(u.getUserId()+"退出系统");
        System.exit(0);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
2.修改:QQView类
在该类中的内层循环中,调用logout方法:
//调用方法,给服务器发送一个退出系统的message
userClientService.logout();

2.服务端:
1.修改:ManageClientThreads类
在该类中增加removeServerConnectClientThread()方法
//增加一个方法,从集合中移除某个对象
public static void removeServerConnectClientThread(String userId){
    hm.remove(userId);
}
2.修改:ServerConnectClientThread类
在该类的run方法中增加业务二操作:
public void run() {//这里线程处于run的状态,可以发送/接收消息
    while (true) {
        try {
            System.out.println("服务端和客户端" + userId + "保持通信,读取数据...");
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            Message message = (Message) ois.readObject();
            //后面会使用message,根据message的类型,做相应的业务处理
            //业务一:客户请求拉取在线用户列表
            if (message.getMesType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)) {
                //客户请求拉取在线用户列表
                //假定返回的用户列表是用空格隔开的id名(如:100 200 紫霞仙子 至尊宝 唐僧)
                System.out.println(message.getSender() + " 要在线用户列表");
                String onlineUser = ManageClientThreads.getOnlineUser();
                //返回message
                //构建一个Message对象(这个Message对象包含了在线用户列表信息),返回给客户端
                Message message2 = new Message();
                //设置消息类型--返回的在线用户列表类型-客户端会根据返回的消息类型来进行相应的业务处理
                message2.setMesType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
                message2.setContent(onlineUser);//返回用户消息列表
                //服务器发送的消息的接收者Getter 就是服务器接收的信息 的发送者Sender
                message2.setGetter(message.getSender());
                //返回给客户端
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                oos.writeObject(message2);
            } else if (message.getMesType().equals(MessageType.MESSAGE_CLIENT_EXIT)) {
                //业务二:客户请求退出系统
                System.out.println(message.getSender() + " 退出");
                //将客户端对应的线程从集合中删除
                ManageClientThreads.removeServerConnectClientThread(message.getSender());
                socket.close();//关闭的是当前的线程持有的socket属性
                //退出线程的循环
                break;
            } else {
                System.out.println("其他类型的message,暂时不处理");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
运行:
1.运行服务端:

2.运行客户端,登录两个用户:


3.查看当前用户列表,可以看到有两个用户:

3.其中一个用户选择退出系统,可以看到用户正确退出,程序结束运行:

4.在另一个用户中查看当前用户列表,可以看到只剩下一个用户,说明服务端已经成功将退出的用户的线程从集合中删除

4.服务端这边显示该用户正确退出:

day03-2无异常退出的更多相关文章
- .NETCore在析构函数(Finalize)在Linux下引起程序异常退出现象
		
目 录 1. 现象概述... 1 2. 操作数据库的代码... 2 3. 引起的异常... 2 4. 异常信息分析... 3 5. 分析结 ...
 - Nginx问题定位之监控进程异常退出
		
nginx在运行过程中是否稳定,是否有异常退出过?这里总结几项平时会用到的小技巧. 1. 在error.log中查看是否有signal项,如果有,看看signal是多少. 比如,这是一个异常退出的情况 ...
 - MHA监控进程异常退出
		
这两天遇到一个非常诡异的问题,打算和大家分享一下.只所以诡异估计是自己知识面不够吧.线上的MHA一直没有开启自动切换,都是手动切换的,最近开启了自动切换以后,退出securecrt窗口以后发现监控进程 ...
 - Aliyun OSS SDK 异步分块上传导致应用异常退出
		
问题描述: 使用Aliyun OSS SDK的BeginUploadPart/EndUploadPart执行异步分块上传操作,程序出现错误并异常退出! 原因分析: Using .NET Framewo ...
 - android捕获程序异常退出
		
今天看到迅雷动漫里面一个CrashHandler 的类,我猜是崩溃处理类.进去一看.果然.顺便学习一下. Android系统的"程序异常退出",给应用的用户体验造成不良影响.为了捕 ...
 - Android系统的“程序异常退出”[转]
		
在应用运行过程中,有很多异常可能会发生,而我们希望在异常发生的时候第一时间的保存现场. 如何处理未捕获的异常呢? 首先我们要实现一个接口 java.lang.Thread.UncaughtExcep ...
 - hive使用python脚本导致java.io.IOException: Broken pipe异常退出
		
反垃圾rd那边有一个hql,在执行过程中出现错误退出,报java.io.IOException: Broken pipe异常,hql中使用到了python脚本,hql和python脚本最近没有人改过, ...
 - PHP - 用户异常断开连接,脚本强制继续执行,异常退出回调
		
试想如下情况.如果你的用户正在执行一个需要非常长的执行时间的操作.他点了执行了之后,浏览器就开始蛋疼地转.如果执行5分钟,你猜他会干啥,显然会觉得什么狗屎垃圾站,这么久都不响应,然后就给关了.当然这个 ...
 - [典型漏洞分享]YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出【高危】
		
YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出[高危] 问题描述: YS VTM模块开放对外监听端口(8554和8664),此次使用sulley fuzzing框架对监听在8664端口 ...
 
随机推荐
- 测试人员假装自己会“devops”
			
目录 什么是DevOps DevOps岗位职责 DevOps的要求 如何增强DevOps能力 准备 服务器端安装jenkins Jenkins jenkins + maven 构建 jenkins下m ...
 - appium实现简单的功能测试
			
实现思路 思路: 1.获取capabilities信息 2.启动app(包含安装过程) 3.检查是否安装成功 4.卸载app 5.检查是否卸载成功 6.执行×3 from time import sl ...
 - Linux shell脚本进阶使用
			
shell的循环控制语句 - continue:提前结束某次循环,重新开始下一次 - break:提前结束某层循环 范例: #求100以内的奇数和 #!/bin/bash sum=0 for i in ...
 - elasticsearchTemplate that could not be found
			
***************************APPLICATION FAILED TO START*************************** Description: Metho ...
 - Redis配置与优化
			
一.缓存概念 缓存是为了调节速度不一致的两个或多个不同的物质的速度,在中间对速度较慢的一方起到加速作用,比如CPU的一级.二级缓存是保存了CPU最近经常访问的数据,内存是保存CPU经常访问硬盘的数据, ...
 - 2022-07-21 第四组 java之继承
			
目录 一.继承 1.概念 2.语法 3.父类成员访问 3.1 子类访问父类的成员变量 3.1.1 子类和父类中不存在同名的成员变量 3.1.2 子类和父类中不存在同名的成员变量 3.2 子类中访问父类 ...
 - 基于MIndSpore框架的道路场景语义分割方法研究
			
基于MIndSpore框架的道路场景语义分割方法研究 概述 本文以华为最新国产深度学习框架Mindspore为基础,将城市道路下的实况图片解析作为任务背景,以复杂城市道路进行高精度的语义分割为任务目标 ...
 - 基于ABP实现DDD--实体创建和更新
			
本文主要介绍了通过构造函数和领域服务创建实体2种方式,后者多用于在创建实体时需要其它业务规则检测的场景.最后介绍了在应用服务层中如何进行实体的更新操作. 一.通过构造函数创建实体 假如Issue的 ...
 - React报错之Object is possibly null
			
正文从这开始~ 类型守卫 使用类型守卫来解决React中useRef钩子"Object is possibly null"的错误.比如说,if (inputRef.current) ...
 - js屏蔽浏览器默认事件
			
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...