修改
MessageType.java
package com.ming.qqcommon;
/**
* @Author: mei_ming
* @DateTime: 2022/10/2 18:31
* @Description: 表示消息类型
*/
public interface MessageType {
String MESSAGE_LOGIN_SUCCEED = "1"; // 登录成功
String MESSAGE_LOGIN_FAIL = "2"; // 登录失败
String MESSAGE_COMM_MES = "3"; //普通信息包
String MESSAGE_GET_ONLINE_FRIEND = "4"; //要求返回在线用户列表
String MESSAGE_RET_ONLINE_FRIEND = "5"; //返回在线用户列表
String MESSAGE_CLIENT_EXIT = "6"; //客户端请求退出
}
UserClientService.java : 新增onlineFriendList()方法
package com.ming.qqclient.service;
import com.ming.qqcommon.Message;
import com.ming.qqcommon.MessageType;
import com.ming.qqcommon.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* @Author: mei_ming
* @DateTime: 2022/10/2 20:13
* @Description: 用户登录、注册等功能的实现类
*/
public class UserClientService {
//因为我们可能在其他地方使用user信息,因此作为成员属性
private User u = new User();
//因为Socket在其他地方也有可能使用
private Socket socket;
//根据userId 和 pwd 到服务器验证该用户是否合法
public boolean checkUser(String userId,String pwd){
boolean b = false;
//创建User对象
u.setUserId(userId);
u.setPasswd(pwd);
try {
//连接到服务端,发送User对象 u
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
//得到ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(u);
//读取从服务器回复的Message对象
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message =(Message) ois.readObject();
if (message.getMesType().equals(MessageType.MESSAGE_LOGIN_SUCCEED)){ //登录成功
//创建一个和服务器端保持通信的线程 ClientConnectServerThread 类
//将socket放入线程中
ClientConnectServerThread connectServerThread = new ClientConnectServerThread(socket);
connectServerThread.start();
//将线程放在集合中
ManageClientConnectServerThread.addClientConnectServerThread(userId,connectServerThread);
b=true;
}else{ //登录失败
//关闭socket
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return b;
}
//向服务端请求在线用户列表
public void onlineFriendList(){
//发送一个Message,类型是
Message message = new Message();
message.setMesType(MessageType.MESSAGE_GET_ONLINE_FRIEND);
message.setSender(u.getUserId());
//发送给服务端
try {
//1. 从管理线程的集合中,通过userId,得到这个 线程 对象
ClientConnectServerThread clientConnectServerThread = ManageClientConnectServerThread.getClientConnectServerThread(u.getUserId());
//2. 得到当前线程的 Socket
Socket socket = clientConnectServerThread.getSocket();
//3. 得到当前Socket相关联的 ObjectOutPutStream
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//向服务端 发送 Message
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientConnectServerThread.java : 在run方法里面改动
package com.ming.qqclient.service;
import com.ming.qqcommon.Message;
import com.ming.qqcommon.MessageType;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
/**
* @Author: mei_ming
* @DateTime: 2022/10/2 20:25
* @Description: 线程生成类
*/
public class ClientConnectServerThread extends Thread{
//该线程需要持有Socket
private Socket socket;
//构造器可以接受一个Socket对象
public ClientConnectServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//因为Thread需要在后台和服务器通信,所以用while
while(true){
try {
System.out.println("客户端线程,等待读取从服务端发送的消息");
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
//读取message,判断类型,做相应的处理
if (message.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)){
//读取到 '在线用户列表'对应的值
//取出在线列表,并打印
String[] onlineUsers = message.getContent().split(" ");
System.out.println("\n========当前在线用户列表========");
for (int i = 0; i <onlineUsers.length ; i++) {
System.out.println("用户: "+onlineUsers[i]);
}
}else{
System.out.println("是其他类型的message,暂不处理");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
}
QQView.java : 调用UserClientService中onlineFriendList()方法
switch (key){
case "1":
//调用UserClientService中的方法:
userClientService.onlineFriendList();
break;
case "2":
System.out.println("群发消息");
break;
case "3":
System.out.println("私聊消息");
break;
case "4":
System.out.println("发送文件");
break;
case "9":
System.out.println("退出系统");
loop=false;
break;
}
ServerConnectClientThread.java : 判断传递的MessageType是否为MESSAGE_GET_ONLINE_FRIEND
package com.ming.qqserver.service;
import com.ming.qqcommon.Message;
import com.ming.qqcommon.MessageType;
import com.sun.deploy.net.proxy.ProxyUnavailableException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
/**
* @Author: mei_ming
* @DateTime: 2022/10/2 21:09
* @Description: 该类的一个对象和某个客户端保持通信
*/
public class ServerConnectClientThread extends Thread {
private Socket socket;
private String userId; //区分是哪一个客户端
public ServerConnectClientThread(Socket socket, String userId) {
this.socket = socket;
this.userId = userId;
}
@Override
public void run() { //这里线程处于run的状态,可以发送/接收消息
while(true){
try {
System.out.println("服务端和客户端"+userId+"保持通信,读取数据....");
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
//根据message类型,做相应的业务处理
if (message.getMesType().equals(MessageType.MESSAGE_GET_ONLINE_FRIEND)){
//客户端要在线用户列表
// 格式 "100 200 孙悟空"
System.out.println(message.getSender() + " 要在线用户列表");
String onlineUser = ManageClientThreads.getOnlineUser();
//返回message
Message message2 = new Message();
message2.setMesType(MessageType.MESSAGE_RET_ONLINE_FRIEND);
message2.setContent(onlineUser);
message2.setGetter(message.getSender());
//返回客户端
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message2);
}else{
System.out.println("是其他类型的message,暂不处理");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
ManageClientThreads.java : 新增getOnlineUser()方法用于获取在线用户
package com.ming.qqserver.service;
import java.util.HashMap;
import java.util.Iterator;
/**
* @Author: mei_ming
* @DateTime: 2022/10/2 21:20
* @Description: 该类用于管理和客户端通信的线程
*/
public class ManageClientThreads {
private static HashMap<String,ServerConnectClientThread> hm=new HashMap<>();
//添加线程到hm中
public static void addServerConnectClientThread(String userId,ServerConnectClientThread serverConnectClientThread){
hm.put(userId,serverConnectClientThread);
}
//根据userId返回ServerConnectClientThread线程
public static ServerConnectClientThread getServerConnectClientThread(String userId){
return hm.get(userId);
}
//返回在线列表
public static String getOnlineUser(){
//集合遍历
Iterator<String> iterator = hm.keySet().iterator();
String onlineUserList = "";
while(iterator.hasNext()){
onlineUserList += iterator.next()+" ";
}
return onlineUserList;
}
}
运行结果