1、使用技术
- Java面向对象编程
- 网络编程
- 多线程
- IO流
- 集合
2、项目功能
?1、用户登录 ?2、拉取在线用户列表 ?3、无异常退出(客户端,服务端) ?4、思路 ?5、群聊 ?6、发文件 ?7、服务器推送新闻
3、项目效果
服务端
(1)启动服务端
客户端
(1)启动客户端
??启动多个客户端
(2)登录成功
??这里我登录三个用户
(3) 显示在线用户列表
(4)群发消息
??其他用户收到群发消息
(5)私聊消息
??被私聊的用户收到消息
(6)发送文件
??其他用户收到
(7)离线私聊
??发送方 ??接收方登录上线
4、项目代码
(1)客户端
??项目结构
1、QQView 客户端界面类
public class QQView {
private boolean loop = true;
private String key = "";
private UserClientService userClientService = new UserClientService();
private MessageService messageService = new MessageService();
private ClientFileService clientFileService = new ClientFileService();
private void mainMenu() {
while (loop) {
System.out.println("============欢迎登录网络通信系统============");
System.out.println("\t\t 1 登录系统");
System.out.println("\t\t 9 退出系统");
System.out.print("请输入你的选择:");
key = Utility.readString();
switch (key) {
case "1":
System.out.print("请输入用户号:");
String uid = Utility.readString();
System.out.print("请输入密 码:");
String password = Utility.readString();
if (userClientService.checkUser(uid,password)) {
messageService.removeMsg(uid);
System.out.println("============欢迎(用户" + uid + ")登录成功============");
while (loop) {
System.out.println("============网络通信系统二级菜单(用户" + uid + ")============");
System.out.println("\t\t 1 显示在线用户列表");
System.out.println("\t\t 2 群发消息");
System.out.println("\t\t 3 私聊消息");
System.out.println("\t\t 4 发送文件");
System.out.println("\t\t 9 退出系统");
System.out.print("请输入你的选择:");
key = Utility.readString();
switch (key) {
case "1":
userClientService.getUsers(uid);
break;
case "2":
System.out.println("\n请输入你的群发内容");
String contentAll = Utility.readString();
messageService.sendMsg(contentAll,uid);
break;
case "3":
System.out.println("\n请输入你要聊天的用户号(在线):");
String getter = Utility.readString();
System.out.println("\n请输入你要私聊的内容");
String content = Utility.readString();
messageService.sendMsg(content,getter,uid);
break;
case "4":
System.out.print("请输入你想把文件发送给的用户(在线用户):");
getter = Utility.readString();
System.out.print("请输入发送文件的路径(形式如 d:\\xx.jpg):");
String src = Utility.readString();
System.out.print("请输入把文件发送到对方的路径(形式如 d:\\xx.jpg):");
String dest = Utility.readString();
clientFileService.sendFileToOne(src,dest,uid,getter);
break;
case "9":
loop = false;
System.out.println("客户端退出系统");
userClientService.exit(uid);
break;
default:
System.out.println("输入错误");
}
}
} else {
System.out.println("登录失败");
}
break;
case "9":
loop = false;
System.out.println("客户端退出系统");
System.exit(0);
break;
default:
System.out.println("输入有误");
}
}
}
public static void main(String[] args) {
new QQView().mainMenu();
}
}
2、Utility 工具类,接收键盘输入
public class Utility {
private static Scanner sc = null;
static {
sc = new Scanner(System.in);
}
public static String readString(){
String next = sc.nextLine();
return next;
}
}
3、UserClientService 用户请求处理类
public class UserClientService {
private User user = new User();
private Socket socket;
public boolean checkUser(String userId,String pwd){
boolean flag = false;
user.setUserId(userId);
user.setPassword(pwd);
try {
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(user);
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message)ois.readObject();
if(MessageType.MESSAGE_LOGIN_SUCCESS.equals(message.getMsgType())){
if (!("".equals(message.getContent()))){
System.out.println("亲,你有离线留言信息哦");
System.out.println(message.getContent());
}
ClientConnectServerThread clientConnectServerThread = new ClientConnectServerThread(socket);
clientConnectServerThread.start();
ManageClientConnectServerThread.addClientConnectServerThread(userId,clientConnectServerThread);
flag = true;
}else {
socket.close();
return false;
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
public void getUsers(String userId){
Message message = new Message();
message.setSender(userId);
message.setMsgType(MessageType.MESSAGE_GET_ONLINE_FRIEND);
try {
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread
.getClientConnectServerThread(userId)
.getSocket()
.getOutputStream());
oos.writeObject(message);
} catch (Exception e) {
e.printStackTrace();
}
}
public void exit(String userId){
Message message = new Message();
message.setSender(userId);
message.setMsgType(MessageType.MESSAGE_CLIENT_EXIT);
try {
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread
.getClientConnectServerThread(userId)
.getSocket()
.getOutputStream());
oos.writeObject(message);
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4、MessageService 消息请求处理类
public class MessageService {
public void sendMsg(String content,String getter,String userId){
Message message = new Message();
message.setMsgType(MessageType.MESSAGE_COMM_MES);
message.setSender(userId);
message.setContent(content);
message.setGetter(getter);
message.setSendTime(new Date().toString());
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(
ManageClientConnectServerThread.getClientConnectServerThread(
userId)
.getSocket()
.getOutputStream());
oos.writeObject(message);
}catch (Exception e){
e.printStackTrace();
}
}
public void sendMsg(String content,String userId){
Message message = new Message();
message.setMsgType(MessageType.MESSAGE_COMM_MES_ALL);
message.setContent(content);
message.setGetter("所有人");
message.setSender(userId);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(
ManageClientConnectServerThread.getClientConnectServerThread(userId).getSocket().getOutputStream());
oos.writeObject(message);
}catch (Exception e){
e.printStackTrace();
}
}
public void removeMsg(String userId){
try {
Message message = new Message();
message.setSender(userId);
message.setMsgType(MessageType.MESSAGE_REMOVE_MSG);
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread.getClientConnectServerThread(userId).getSocket().getOutputStream());
oos.writeObject(message);
}catch (Exception e){
e.printStackTrace();
}
}
}
5、ClientFileService 文件请求处理类
public class ClientFileService {
public void sendFileToOne(String src,String dest,String senderId,String getterId){
Message message = new Message();
message.setMsgType(MessageType.MESSAGE_SENDFILE);
message.setSender(senderId);
message.setGetter(getterId);
message.setDest(dest);
message.setSrc(src);
int fileLen = (int) new File(src).length();
byte[] fileBytes = new byte[fileLen];
FileInputStream fis = null;
try {
fis = new FileInputStream(src);
fis.read(fileBytes);
message.setFileBytes(fileBytes);
message.setFileLen(fileLen);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (fis != null) fis.close();
}catch (Exception e){
e.printStackTrace();
}
}
System.out.println("\n" + senderId + "给" + getterId + " 发送文件 " + src + " 到对方电脑的目录 " +dest);
try {
ObjectOutputStream oos = new ObjectOutputStream(ManageClientConnectServerThread
.getClientConnectServerThread(senderId)
.getSocket()
.getOutputStream());
oos.writeObject(message);
}catch (Exception e){
e.printStackTrace();
}
}
}
6、ManageClientConnectServerThread 管理客户端连接到服务端的线程 的类
public class ManageClientConnectServerThread {
private static HashMap<String,ClientConnectServerThread> hm = new HashMap<>();
public static void addClientConnectServerThread(String userId,ClientConnectServerThread clientThread){
hm.put(userId,clientThread);
}
public static ClientConnectServerThread getClientConnectServerThread(String userId){
return hm.get(userId);
}
}
7、ClientConnectServerThread 客户端连接线程类
public class ClientConnectServerThread extends Thread{
private Socket socket;
public ClientConnectServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
while (true){
try {
System.out.println("客户端线程。等待读取从服务端发送的消息");
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message)ois.readObject();
if (MessageType.MESSAGE_RETURN_ONLINE_FRIEND.equals(message.getMsgType())){
String[] onLine = message.getContent().split(" ");
System.out.println("\n============当前用户在线数============");
for (int i = 0; i < onLine.length; i++) {
System.out.println("用户:"+onLine[i]);
}
}else if(MessageType.MESSAGE_COMM_MES.equals(message.getMsgType())){
System.out.println("\n"+message.getSender()+" 对 "+message.getGetter() + " 说:"+message.getContent());
}else if(MessageType.MESSAGE_COMM_MES_ALL.equals(message.getMsgType())){
System.out.println("\n"+message.getSender()+" 对 "+message.getGetter() + " 说:"+message.getContent());
}else if(MessageType.MESSAGE_SENDFILE.equals(message.getMsgType())){
System.out.println("\n"+message.getSender() + " 给 " + message.getGetter()
+ " 发送了文件,到我的电脑的 "+message.getDest());
FileOutputStream fos = new FileOutputStream(message.getDest());
fos.write(message.getFileBytes());
fos.close();
System.out.println("文件保存成功!");
}else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
(2)服务端
1、Application 服务端启动类
public class Application {
public static void main(String[] args) {
new QQServer();
}
}
2、Utility 工具类
public class Utility {
private static Scanner sc = null;
static {
sc = new Scanner(System.in);
}
public static String readString(){
String next = sc.nextLine();
return next;
}
}
3、QQServer 服务端类
public class QQServer {
private ServerSocket ss = null;
private static HashMap<String,User> validUsers = new HashMap<>();
static {
validUsers.put("123",new User("123","123"));
validUsers.put("admin",new User("admin","123"));
validUsers.put("111",new User("111","123"));
validUsers.put("100",new User("100","123"));
validUsers.put("至尊宝",new User("至尊宝","123"));
validUsers.put("紫霞仙子",new User("紫霞仙子","123"));
validUsers.put("菩提老祖",new User("菩提老祖","123"));
}
private boolean checkUser(String userId,String pwd){
User user = validUsers.get(userId);
if (user == null){
return false;
}else {
if (!(userId.equals(user.getUserId()) && pwd.equals(user.getPassword()))){
return false;
}
}
return true;
}
public QQServer(){
System.out.println("服务端在9999 端口监听");
new Thread(new SendNewsToAllService()).start();
try {
ss = new ServerSocket(9999);
while (true){
Socket socket = ss.accept();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
User user = (User)ois.readObject();
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
if (checkUser(user.getUserId(), user.getPassword())){
Message message = new Message("系统", user.getUserId(), "登录成功", "", MessageType.MESSAGE_LOGIN_SUCCESS);
String msg = ManagerUserMessage.getMessage(user.getUserId());
if (!("".equals(msg))){
message.setContent(msg);
}
oos.writeObject(message);
ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket,user.getUserId());
serverConnectClientThread.start();
ManagerClientThreads.addServerConnectClientThread(user.getUserId(),serverConnectClientThread);
}else {
System.out.println("用户 id="+user.getUserId()+" pwd="+user.getPassword()+" 登录失败");
Message message = new Message("系统", user.getUserId(), "登录失败", "", MessageType.MESSAGE_LOGIN_ERROR);
oos.writeObject(message);
socket.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
ss.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
4、SendNewsToAllService 群发消息类
public class SendNewsToAllService implements Runnable{
@Override
public void run() {
while (true){
System.out.println("请输入服务器要推送的消息【输入exit表示退出推送服务】");
String msg = Utility.readString();
if ("exit".equals(msg)) {
break;
}
Message message = new Message();
message.setSender("服务器");
message.setContent(msg);
message.setGetter("大家");
message.setSendTime(new Date().toString());
message.setMsgType(MessageType.MESSAGE_COMM_MES_ALL);
System.out.println("服务器推送消息给所有人 说:"+msg);
String users = ManagerClientThreads.getValidUsers();
String[] userIds = users.split(" ");
if (userIds.length > 0){
for (String userId : userIds){
try {
ObjectOutputStream oos = new ObjectOutputStream(ManagerClientThreads
.getServerConnectClientThread(userId)
.getSocket()
.getOutputStream());
oos.writeObject(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
5、ManagerUserMessage 用户请求处理类
public class ManagerUserMessage {
private static HashMap<String, ArrayList<String>> tempMessage;
static {
tempMessage = new HashMap<>();
}
public static void addMessage(String userId,String msg){
ArrayList<String> arrayList = tempMessage.get(userId);
if (arrayList != null){
arrayList.add(msg);
}else {
ArrayList<String> array = new ArrayList<>();
array.add(msg);
tempMessage.put(userId,array);
}
}
public static String getMessage(String userId){
ArrayList<String> arrayList = tempMessage.get(userId);
StringBuffer sb = null;
if (arrayList != null && arrayList.size() > 0){
sb = new StringBuffer();
for (String msg : arrayList){
sb.append(msg).append("\r\n");
}
return sb.toString();
}
return "";
}
public static void removeMessage(String userId){
ArrayList<String> strings = tempMessage.get(userId);
strings = null;
tempMessage.remove(userId);
}
public static HashMap<String, ArrayList<String>> getTempMessage(){
return tempMessage;
}
}
6、ManagerClientThreads 用于管理和客户端通信的线程
public class ManagerClientThreads {
private static HashMap<String,ServerConnectClientThread> hm = new HashMap<>();
public static void addServerConnectClientThread(String userId,ServerConnectClientThread serverConnectClientThread){
hm.put(userId,serverConnectClientThread);
}
public static ServerConnectClientThread getServerConnectClientThread(String userId){
return hm.get(userId);
}
public static String getValidUsers(){
StringBuffer sb = null;
Set<String> userIds = hm.keySet();
if (userIds.size() > 0){
sb = new StringBuffer();
for (String uid : userIds) {
sb.append(uid).append(" ");
}
return sb.toString();
}
return "";
}
public static void removeThread(String uid){
hm.remove(uid);
}
}
7、ServerConnectClientThread 服务端socket类
public class ServerConnectClientThread extends Thread{
private Socket socket;
private String userId;
public ServerConnectClientThread(Socket socket,String userId){
this.socket = socket;
this.userId = userId;
}
public Socket getSocket(){
return socket;
}
@Override
public void run() {
while (true){
try {
System.out.println("服务端数据=======》》");
System.out.println(ManagerUserMessage.getTempMessage());
System.out.println(ManagerClientThreads.getValidUsers());
System.out.println("服务端数据=======》》");
System.out.println("服务端和客户端"+userId+"保持通信,读取数据。。。");
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
if (MessageType.MESSAGE_GET_ONLINE_FRIEND.equals(message.getMsgType())){
String onLineUsers = ManagerClientThreads.getValidUsers();
System.out.println("在线用用户列表"+onLineUsers);
Message msg = new Message();
msg.setMsgType(MessageType.MESSAGE_RETURN_ONLINE_FRIEND);
msg.setContent(onLineUsers);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(msg);
}else if (MessageType.MESSAGE_CLIENT_EXIT.equals(message.getMsgType())){
System.out.println(message.getSender()+" 退出");
ManagerClientThreads.removeThread(message.getSender());
socket.close();
break;
}else if (MessageType.MESSAGE_COMM_MES.equals(message.getMsgType())){
ServerConnectClientThread clientThread = ManagerClientThreads.getServerConnectClientThread(message.getGetter());
if (clientThread == null){
ManagerUserMessage.addMessage(message.getGetter(),message.getContent());
}else {
ObjectOutputStream oos = new ObjectOutputStream(clientThread
.getSocket()
.getOutputStream());
oos.writeObject(message);
}
}else if (MessageType.MESSAGE_COMM_MES_ALL.equals(message.getMsgType())){
String users = ManagerClientThreads.getValidUsers();
String[] userIds = users.split(" ");
if (userIds.length > 0){
for (String uid : userIds){
if (!(uid.equals(message.getSender()))){
ObjectOutputStream oos = new ObjectOutputStream(ManagerClientThreads
.getServerConnectClientThread(uid)
.getSocket()
.getOutputStream());
oos.writeObject(message);
}
}
}
}else if (MessageType.MESSAGE_SENDFILE.equals(message.getMsgType())){
ObjectOutputStream oos = new ObjectOutputStream(ManagerClientThreads
.getServerConnectClientThread(message.getGetter()).getSocket().getOutputStream());
oos.writeObject(message);
}else if (MessageType.MESSAGE_REMOVE_MSG.equals(message.getMsgType())){
ManagerUserMessage.removeMessage(message.getSender());
}
} catch (Exception e) {
e.printStackTrace();
}finally {
}
}
}
}
(3)公共代码
??由于pojo下面的实体类代码是公共的,这里只贴一份
1、Message
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private String sender;
private String getter;
private String content;
private String sendTime;
private String msgType;
private byte[] fileBytes;
private int fileLen = 0;
private String dest;
private String src;
public byte[] getFileBytes() {
return fileBytes;
}
public void setFileBytes(byte[] fileBytes) {
this.fileBytes = fileBytes;
}
public int getFileLen() {
return fileLen;
}
public void setFileLen(int fileLen) {
this.fileLen = fileLen;
}
public String getDest() {
return dest;
}
public void setDest(String dest) {
this.dest = dest;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
@Override
public String toString() {
return "Message{" +
"sender='" + sender + '\'' +
", getter='" + getter + '\'' +
", content='" + content + '\'' +
", sendTime='" + sendTime + '\'' +
", msgType='" + msgType + '\'' +
'}';
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public Message() {
}
public Message(String sender, String getter, String content, String sendTime, String msgType) {
this.sender = sender;
this.getter = getter;
this.content = content;
this.sendTime = sendTime;
this.msgType = msgType;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getGetter() {
return getter;
}
public void setGetter(String getter) {
this.getter = getter;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSendTime() {
return sendTime;
}
public void setSendTime(String sendTime) {
this.sendTime = sendTime;
}
}
2、MessageType
public interface MessageType {
String MESSAGE_LOGIN_SUCCESS = "1";
String MESSAGE_LOGIN_ERROR = "2";
String MESSAGE_COMM_MES = "3";
String MESSAGE_GET_ONLINE_FRIEND = "4";
String MESSAGE_RETURN_ONLINE_FRIEND = "5";
String MESSAGE_CLIENT_EXIT = "6";
String MESSAGE_COMM_MES_ALL = "7";
String MESSAGE_SENDFILE = "8";
String MESSAGE_REMOVE_MSG = "9";
}
3、User
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String userId;
private String password;
public User(String userId, String password) {
this.userId = userId;
this.password = password;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", password='" + password + '\'' +
'}';
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
|