Socket–韩顺平简易网络通信系统
涉及技术
- 面向对象编程
- 网络编程
- 多线程
- IO流
- 集合
- 框架设计
实现功能
- 用户登录
- 拉取在线用户列表
- 无异常退出(客户端, 服务器端)
- 私聊
- 群发
- 发文件
- 服务器端推送消息
实现效果
1.主界面及用户登录
2.拉取在线用户列表
登陆多个用户
3.私聊
发送方
接收方
服务端显示
4.群发消息
发送方
接收者
服务器端显示
5.发送文件
发送方
接收方文件本地地址
服务器端
6.服务器推送消息
服务器端显示
7.离线聊天发送文件
发送方
接收方上线
客户端代码
客户端结构总览
QQView主界面
package com.wu.qqclient.view;
import com.wu.qqclient.service.FileClientService;
import com.wu.qqclient.service.MessageClientService;
import com.wu.qqclient.service.UserClientService;
import com.wu.qqclient.utils.Utility;
/**
* 客户端的显示界面
*/
public class QQView {
private boolean loop = true;//控制主菜单中循环
private String key = "";
private UserClientService userClientService = new UserClientService();//负责登陆,拉取用户列表,退出功能
private MessageClientService messageClientService = new MessageClientService();//消息传输相关功能实现
private FileClientService fileClientService = new FileClientService();
//客户端主函数
public static void main(String[] args) {
new QQView().mainMenu();
System.out.println("退出系统");
}
/**
* 主菜单
*/
private void mainMenu() {
while (loop) {
System.out.println("=============欢迎登录网络通信系统=============");
System.out.println("\t\t\t 1 登录系统");
System.out.println("\t\t\t 9 退出系统");
System.out.print("请输入你的选择:");
key = Utility.readString(1);
switch (key) {
//用户登录
case "1":
System.out.print("请输入用户名: ");
String userId = Utility.readString(50);
System.out.print("请输入密 码: ");
String pwd = Utility.readString(20);
//检测用户名和密码
if (this.userClientService.checkUser(userId, pwd)) {
System.out.println("欢迎" + userId + "用户登录成功");
//二级菜单
while (loop) {
System.out.println("\n=============网络通信系统二级菜单(用户:" + userId + ")=============\"");
System.out.println("\t\t\t 1 显示在线用户列表");
System.out.println("\t\t\t 2 群发消息");
System.out.println("\t\t\t 3 私聊消息");
System.out.println("\t\t\t 4 发送文件");
System.out.println("\t\t\t 9 退出系统");
System.out.print("请输入你的选择: ");
key = Utility.readString(1);
switch (key) {
//拉取在线用户列表
case "1":
userClientService.onlineFriendList();
break;
//群发消息
case "2":
System.out.print("输入群聊消息:");
String info = Utility.readString(50);
messageClientService.groupChat(info, userId);
break;
//发送私聊消息
case "3":
System.out.print("输入想要私聊的用户名(在线): ");
String getterId = Utility.readString(50);
System.out.print("请输入内容");
String content = Utility.readString(100);
messageClientService.privateChat(content, userId, getterId);
break;
//发送文件
case "4":
System.out.print("输入想要发送文件的用户名:");
String fileGetterId = Utility.readString(50);
System.out.print("输入想要传输的文件地址");
String src = Utility.readString(50);
fileClientService.sendFile(src, userId, fileGetterId);
break;
//退出系统
case "9":
userClientService.exitQQClient();
break;
}
}
} else {
System.out.println("=============登 录 失 败=============");
}
break;
case "9":
loop = false;
break;
}
}
}
}
Service服务类
1.UserClientService用户请求处理类
package com.wu.qqclient.service;
import com.wu.qqcommon.Message;
import com.wu.qqcommon.MessageType;
import com.wu.qqcommon.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* 负责用户登陆,拉取在线用户列表,退出系统功能
*/
public class UserClientService {
private User user = new User();
private boolean flag = false;
private Socket socket;
/**
* 检测用户名密码,成功登陆开启socket线程
* @param userId 用户名
* @param pwd 密码
* @return T/F
*/
public boolean checkUser(String userId, String pwd) {
user.setUserId(userId);
user.setPasswd(pwd);
try {
//以本机为服务器.端口为9999的socket对象
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
//得到输出流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//将user传输给服务器
oos.writeObject(user);
//socket输入流
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//读取数据报
Message ms = (Message)ois.readObject();
//登录成功
if (ms.getMesType().equals(MessageType.MESSAGE_LOGIN_SUCCED)) {
//创建一个线程对象
ClientConnectService clientConnectService = new ClientConnectService(socket);
//开启线程
clientConnectService.start();
//将线程加入线程池中,以userId(用户名)为键值,线程对象为Value
ManageClientConnectServiceThread.addClientConnectServiceThread(userId, clientConnectService);
//成功登陆,返回值设为true
flag = true;
} else {
//登录失败,关闭socket
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
//返回值
return flag;
}
/**
* 拉取在线用户列表
*/
public void onlineFriendList() {
Message message = new Message();//创建一个数据报对象message
message.setMesType(MessageType.MESSAGE_GET_ONLINE_FRIEND);//设置消息雷响
message.setSender(user.getUserId());//设置发送用户信息
try {
//通过用户名得到线程池中对应线程,再通过该线程得到的socket对象get输出流
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServiceThread.
getClientConnectServiceThread(this.user.getUserId()).getSocket().getOutputStream());
//写入数据
oos.writeObject(message);
} catch (IOException var3) {
var3.printStackTrace();
}
}
/**
* 退出客户端下线
*/
public void exitQQClient() {
Message message = new Message();
message.setMesType(MessageType.MESSAGE_CLIENT_EXIT);//消息类型
message.setSender(user.getUserId());//发送者信息
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
System.out.println("用户:"+user.getUserId()+"退出系统");
//ManageClientConnectServiceThread.removeClientServiceThread(user.getUserId());
System.exit(0);//退出
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.ClientConnectService客户端连接线程类
package com.wu.qqclient.service;
import com.wu.qqcommon.Message;
import com.wu.qqcommon.MessageType;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.net.Socket;
/**
* 客户端socket通信线程,监听接收并根据消息类型做出反馈
*/
public class ClientConnectService extends Thread {
private Socket socket;
//private ObjectInputStream ois = null;
public ClientConnectService(Socket socket) {
this.socket = socket;
}
//线程
@Override
public void run() {
while (true) {
try {
//创建输入流
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//读取对象
Message message = (Message) ois.readObject();
//拉取用户列表
if (message.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)) {
System.out.println("\n当前在线用户列表:");
String[] onlineUsers = message.getContent().split(" ");
for (String s : onlineUsers) {
System.out.println("用户: " + s);
}
//私聊消息
} else if (message.getMesType().equals(MessageType.MESSAGE_COMM_MES)) {
System.out.println("\n" + message.ge