package qqServer.server;
import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import qqCommon.Message;
import qqCommon.MessageType;
import qqServer.Utils.MyObjectInputStream;
import qqServer.Utils.MyObjectOutputStream;
import qqServer.view.ServerFrame;
/**
*
* @author sky
* @version 1.0
*
* 服务端线程类
* 1.接收拉取在线用户请求, 返回message给原用户
* 2.接收私聊请求, 发送信息包给指定用户
* 3.接收群聊请求, 发送消息包给所有在线用户
* 4.接收私发文件请求
* 5.接收群发文件请求
* 6.接收(线程)退出请求, 将信息发送给其线程提示退出, 并break退出该线程 关闭socket
* 包括 聊天窗口(线程)退出 和 客户端退出
*
*/
public class ServerConnectThread extends Thread{
private ServerFrame serverFrame = null; // 服务端界面对象
private Socket socket; // 类即客户端 的socket
private String userId; // 连接到的服务端 的对应用户id, 方便识别
// 构造器 初始化传入
public ServerConnectThread(Socket socket, String userId, ServerFrame serverFrame) {
super();
this.socket = socket;
this.userId = userId;
this.serverFrame = serverFrame;
}
// get方法
public Socket getSocket() {
return socket;
}
// 不停 接收读取 客户端发送 的数据
@Override
public void run() {
// 线程处于run状态, 可以循环 方式/接收 客户端信息, 保持通信
while(true) {
println("服务端和 " + userId + " 保持通信, 读取数据");
try {
MyObjectInputStream ois =
new MyObjectInputStream(socket.getInputStream());
// 若 客户端没有发送对象, 则重写在此阻塞(暂停)
Message message = (Message) ois.readObject();
// 对接收的messageType 类型进行判断,进行相应操作
if(message.getMessType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)) {
// 一. 接到客户端 拉取在线用户列表 的请求
/*
* 线程管理类ServerConnectClientThreadManage 存储所有userId
* 调用其 getOnlineUsers()方法 得到userId组成的字符串
*/
String onlineUsers = ServerConnectThreadManage.getOnlineUsers();
Message message2 = new Message();
message2.setContent(onlineUsers); // 设置发送内容 在线用户
message2.setSendTime(message.getSendTime());
message2.setMessType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
message2.setSender(message.getSender()); // 设置发送者 (为发过去的客户端)
println("客户端 " + userId + " 正在拉取在线用户列表....");
MyObjectOutputStream oos =
new MyObjectOutputStream(socket.getOutputStream());
oos.writeObject(message2); // 写入
} else if (message.getMessType().equals(MessageType.MESSAGE_COMM_MES)) {
// 二. 普通消息 客户端私聊
// 调用 线程管理类的 getThread()方法 获取--接收者-- 的线程
ServerConnectThread thread
= ServerConnectThreadManage.getThread( message.getGetter(), message.getSender());
if(thread != null) { // 线程存在
MyObjectOutputStream oos =
new MyObjectOutputStream(thread.getSocket().getOutputStream());
oos.writeObject(message); // 写入
println(message.getSender() + " 向 "
+ message.getGetter() + " 发送消息." );
} else {
// 对方未启动 对应线程
println(message.getSender() + " 向 " + message.getGetter() + " 发送消息失败!");
}
} else if (message.getMessType().equals(MessageType.MESSAGE_ToAll_MES)) {
// 三. 客户端群聊
/*
* 需要遍历 线程管理类的集合 得到 所有线程socket
* 调用 其getThread()方法 取得 该用户的线程集合
*/
HashMap<String, HashMap<String, ServerConnectThread>> map =
ServerConnectThreadManage.getMap();
// 遍历集合
Iterator<String> iterator = map.keySet().iterator();
String onlineUserId;
while(iterator.hasNext()) {
onlineUserId = iterator.next().toString(); // 取出在线用户的id 即为iterator
// 在线用户不是 客户端发送方
if(! onlineUserId.equals(message.getSender())) {
message.setGetter(onlineUserId);
// 取出群聊线程
ServerConnectThread thread = map.get(onlineUserId).get("群聊");
if(thread != null) {
MyObjectOutputStream oos = // 取得该用户线程集合 取群聊线程 取io流
new MyObjectOutputStream(thread.getSocket().getOutputStream());
oos.writeObject(message);
println("用户 " + message.getSender() + " 向所有人群发消息, 用户"
+ onlineUserId + " 接收成功.");
} else {
println(message.getSender() + " 向所有人 群发消息, 用户 "
+ onlineUserId + " 接收失败!");
}
}
}
} else if (message.getMessType().equals(MessageType.MESSAGE_File_MES)) {
// 四. 客户端 私聊传输文件
String getterId = message.getGetter();
/* 线程管理类的getThread()方法 获取线程
*/
ServerConnectThread thread = // 接收方 接收方聊天对象(发送方)
ServerConnectThreadManage.getThread(getterId, userId);
if(thread != null) { // 线程存在
MyObjectOutputStream oos =
new MyObjectOutputStream(thread.getSocket().getOutputStream());
oos.writeObject(message);
println(message.getSender() + " 向 " + message.getGetter() + " 发送文件...");
} else {
// 对方未启动 对应线程
println(message.getSender() + " 向 " + message.getGetter() + " 发送文件失败!");
}
} else if (message.getMessType().equals(MessageType.MESSAGE_File_MES_TOALL)) {
// 五. 客户端群发文件
// 定义消息类型 为文件传输 (客户端接收不分 群发/私发)
message.setMessType(MessageType.MESSAGE_File_MES);
/*
* 需要遍历 线程管理类的集合 得到 所有线程socket
* 调用 getThread()方法 取得hashmap集合
*/
HashMap<String, HashMap<String, ServerConnectThread>> map =
ServerConnectThreadManage.getMap();
// 遍历集合
Iterator<String> iterator = map.keySet().iterator();
String onlineUserId;
while(iterator.hasNext()) {
// 取出在线用户的id 即为iterator
onlineUserId = iterator.next().toString();
// 在线用户不是 客户端发送方, 发送
if(! onlineUserId.equals(message.getSender())) {
message.setGetter(onlineUserId);
ServerConnectThread thread = map.get(onlineUserId).get("群聊");
if(thread != null) {
MyObjectOutputStream oos = // 取得该用户线程集合 取群聊线程 取io流
new MyObjectOutputStream(thread.getSocket().getOutputStream());
oos.writeObject(message);
// 打印文件名
println("用户 " + message.getSender() + " 向所有人群发文件:\n"
+ message.getFileName() + " 接收用户: " + onlineUserId);
} else {
println(message.getSender() + " 向所有人 群发文件, 用户 "
+ onlineUserId + " 接收失败!");
}
}
}
} else if (message.getMessType().equals(MessageType.MESSAGE_CLIENT_EXIT)) {
// 六. 接到 客户端准备退出 系统, 将message返回给客户端线程, 再关闭socket
/* 客户端 调用userClientService类 的 logout()方法向服务端发送退出提示 无异常退出
*
* 否则 服务端会报错: java.net.SocketException:Connection reset
* 报错位置: at qqServer.server.ServerConnectClientThread.run(ServerConnectClientThread.java:60)
* (服务端接收到后会将message返回给 本客户端线程-提醒其退出, 再关闭服务端对应socket)
*/
ServerConnectThread thread = ServerConnectThreadManage.
getThread(message.getSender(), message.getGetter());
MyObjectOutputStream oos =
new MyObjectOutputStream(thread.getSocket().getOutputStream());
oos.writeObject(message);
// 将客户端对应的线程从集合中 删除
if(me
Java多用户即时通信
需积分: 0 145 浏览量
更新于2022-12-23
2
收藏 297KB ZIP 举报
在IT行业中,构建一个多用户即时通信系统是一项常见的任务,特别是在开发聊天应用或者协作工具时。本项目"Java多用户即时通信"就是这样一个系统,它利用了Java的基础特性,包括Socket编程、Swing库用于GUI设计,以及多线程技术,来实现客户端之间的私聊、群聊以及文件传输功能。
我们来详细了解一下Java Socket编程。Socket是网络编程中的基本概念,它是两台计算机之间通信的桥梁。在Java中,Socket类提供了创建和管理网络连接的能力。在这个项目中,服务器端通过Socket监听特定端口,等待客户端的连接请求。当客户端发起连接后,服务器端接受连接,并为每个客户端创建一个新的Socket实例,以便进行单独的数据交换。客户端则通过Socket与服务器建立连接,发送和接收消息。
Swing是Java提供的一个用于创建桌面应用程序的GUI(图形用户界面)库。在这个即时通信系统中,Swing被用来设计用户友好的交互界面,包括登录窗口、主聊天窗口、用户列表、私聊窗口等。开发者可以使用JFrame、JPanel、JButton、JLabel、JTextArea等组件来构建这些界面,同时结合ActionListener等事件监听器处理用户的交互行为。
多线程是实现并发处理的关键技术,在这个项目中,多线程被用来处理不同的任务,如接收和发送消息、处理文件传输、更新用户界面等。通常,一个线程负责读取Socket上的数据,另一个线程负责处理UI更新,避免因为I/O操作阻塞用户界面。此外,对于群聊和私聊,可能还需要为每个会话创建独立的线程,以确保消息的实时性和并发性。
文件传输功能是即时通信系统的一个重要组成部分。在Java中,这可以通过输入/输出流(InputStream/OutputStream)来实现。服务器端接收客户端发送的文件,将其保存到本地,然后根据需要再发送给其他客户端。为了确保文件传输的正确性和完整性,可以使用字节流配合缓冲区进行大文件的分块传输,并在接收端进行校验。
除了以上核心技术,项目可能还涉及到其他方面,如身份验证(可能使用用户名和密码)、消息序列化(将消息转化为可传输的字节序列)、错误处理(如网络中断、文件传输失败等)以及性能优化(如使用线程池管理并发线程)。"Java多用户即时通信"项目集成了多种Java编程的核心技术和实践,是一个很好的学习和提升Java网络编程、GUI设计以及多线程应用的实战案例。

尘下吹霜
- 粉丝: 575
最新资源
- 基于PLC的掘进机电控系统设计张宏强.docx
- 网络营销-Microsoft-Word-文档.doc
- 杭浦高速公路项目管理手册样本.doc
- 工字钢井架工艺编程.doc
- 环境信息化现状评估报告.doc
- 园区网络主干光缆敷设及分中心机房建设方案.doc
- 网络维护简历模板.doc
- 网销亿网络营销技能之推广技巧.pptx
- 工程硕士项目管理.docx
- 基于单片机的交通灯控制系统的设计.docx
- 网络舆情管理课件--网络舆情分析与媒体应对.ppt
- 精华版国家开放大学电大专科《网络应用服务管理》判断题题库及答案.docx
- 土木工程知识点-建设监理中的质量控制与项目管理中的质量管理比较.doc
- 基于51单片机的秒表设计.doc
- 全年系统集成项目管理工程师试题分析与解答.doc
- 关于国家电力公司系统安全监督机构的设置问题.doc