多用户即时通讯系统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无异常退出的更多相关文章

  1. .NETCore在析构函数(Finalize)在Linux下引起程序异常退出现象

    目       录 1.      现象概述... 1 2.      操作数据库的代码... 2 3.      引起的异常... 2 4.      异常信息分析... 3 5.      分析结 ...

  2. Nginx问题定位之监控进程异常退出

    nginx在运行过程中是否稳定,是否有异常退出过?这里总结几项平时会用到的小技巧. 1. 在error.log中查看是否有signal项,如果有,看看signal是多少. 比如,这是一个异常退出的情况 ...

  3. MHA监控进程异常退出

    这两天遇到一个非常诡异的问题,打算和大家分享一下.只所以诡异估计是自己知识面不够吧.线上的MHA一直没有开启自动切换,都是手动切换的,最近开启了自动切换以后,退出securecrt窗口以后发现监控进程 ...

  4. Aliyun OSS SDK 异步分块上传导致应用异常退出

    问题描述: 使用Aliyun OSS SDK的BeginUploadPart/EndUploadPart执行异步分块上传操作,程序出现错误并异常退出! 原因分析: Using .NET Framewo ...

  5. android捕获程序异常退出

    今天看到迅雷动漫里面一个CrashHandler 的类,我猜是崩溃处理类.进去一看.果然.顺便学习一下. Android系统的"程序异常退出",给应用的用户体验造成不良影响.为了捕 ...

  6. Android系统的“程序异常退出”[转]

    在应用运行过程中,有很多异常可能会发生,而我们希望在异常发生的时候第一时间的保存现场. 如何处理未捕获的异常呢? 首先我们要实现一个接口  java.lang.Thread.UncaughtExcep ...

  7. hive使用python脚本导致java.io.IOException: Broken pipe异常退出

    反垃圾rd那边有一个hql,在执行过程中出现错误退出,报java.io.IOException: Broken pipe异常,hql中使用到了python脚本,hql和python脚本最近没有人改过, ...

  8. PHP - 用户异常断开连接,脚本强制继续执行,异常退出回调

    试想如下情况.如果你的用户正在执行一个需要非常长的执行时间的操作.他点了执行了之后,浏览器就开始蛋疼地转.如果执行5分钟,你猜他会干啥,显然会觉得什么狗屎垃圾站,这么久都不响应,然后就给关了.当然这个 ...

  9. [典型漏洞分享]YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出【高危】

    YS VTM模块存在格式化字符串漏洞,可导致VTM进程异常退出[高危] 问题描述: YS VTM模块开放对外监听端口(8554和8664),此次使用sulley fuzzing框架对监听在8664端口 ...

  10. 程序异常退出 却没有产生core文件

    程序异常退出  却没有产生core文件 http://www.cnblogs.com/my_life/articles/4107333.html

随机推荐

  1. Linq 多条件连接

    var total = (from a in all                              join g in group_M                            ...

  2. JavaScript 类型转换

    在 JavaScript 中有 5 中不同的数据类型: string number boolean object function 3 种对象类型: Object Date Array 2 个不包含任 ...

  3. Django里面的RequestContext

    c = RequestContext(request, { 'foo': 'bar', }) get_template('about.html').render(c) 当我们定义一个RequestCo ...

  4. PAT (Advanced Level) 1104. Sum of Number Segments (20)

    简单题. #include<cstdio> #include<cstring> #include<cmath> #include<vector> #in ...

  5. webpack2使用ch4-向根目录index.html文件传参并使用参数 使用线上资源 压缩html

    1 webpack.config.js const webpack = require('webpack'), htmlWebpackPlugin = require('html-webpack-pl ...

  6. 与下位机或设备的通信解析优化的一点功能:T4+动态编译

        去年接触的一个项目中,需要通过TCP与设备进行对接的,传的是Modbus协议的数据,然后后台需要可以动态配置协议解析的方式,即寄存器的解析方式,,配置信息有:Key,数据Index,源数据类型 ...

  7. java如何编写下载功能

    @RequestMapping("/downLoadFailRecord") public ModelAndView downLoadFailRecord( HttpServlet ...

  8. SNK 与PFX

    snk 1用来证明这个生成的程序集是你发布的: 2如果你写的程序集要用在多个应用程序上的话,那么这个程序集必须要拥有唯一的名称,这个强名称是程序集唯一名称的一部分. 3只要你保护好你的snk文件不要公 ...

  9. 数据仓库建模与ETL的实践

    一.Data仓库的架构 Data仓库(Data Warehouse DW)是为了便于多维分析和多角度展现而将Data按特定的模式进行存储所建立起来的关系型Datcbase,它的Data基于OLTP源S ...

  10. Supervisor 进程管理工具

    简介: Supervisor 进程管理工具 一.安装 shell > yum -y install python-pip shell > pip install supervisor # ...