多用户及时通信系统

目录

  • 1. QQ用户登录
    • 1.1 用户登录1
    • 1.2 用户登录2
    • 1.3 用户登录3
  • 2. 拉取在线用户
    • 3. 无异常退出
    • 4. 私聊系统
    • 5. 群聊
  • 3. 发送文件
    • 3.1 服务端推送新闻
    • 3.2 离线留言和离线发文件

1. QQ用户登录

多用户及时通信系统_第1张图片

1.1 用户登录1

  • qqcommon包下
    User类序列化
    多用户及时通信系统_第2张图片
    Message消息类序列化
    多用户及时通信系统_第3张图片
    MessType接口
    多用户及时通信系统_第4张图片
  • qqclient.utils包下
    Utility.java工具类
  • qqclient.view包下
public class QQView {
    private User u = new User();
    private String key = "";//接受用户键盘输入
    private boolean loop = true;//控制循环

    public static void main(String[] args) {
        new QQView().mainMenu();
        System.out.println("客户端退出");
    }

    public void mainMenu() {
        while (loop) {
            System.out.println("==============欢迎登陆网络通信系统==============");
            System.out.println("\t\t1 登录系统");
            System.out.println("\t\t9 退出系统");
            System.out.print("请输入你的选择: ");
            key = Utility.readString(1);
            switch (key) {
                case "1":
                    System.out.print("请输入你的用户名: ");
                    String userId = Utility.readString(50);
                    System.out.print("请输入你的密码: ");
                    String password = Utility.readString(50);
                    //设计一个类,验证用户名密码
                    if (false) {
                        System.out.println("==============欢迎(用户 " + userId + " 登录成功)==============");
                        //进入二级菜单
                        while (loop) {
                            System.out.println("\n==============网络通信系统二级菜单(用户 " + userId + " )==============");
                            System.out.println("\t\t1 显示在线用户列表");
                            System.out.println("\t\t2 群发消息");
                            System.out.println("\t\t3 私聊消息");
                            System.out.println("\t\t4 发送文件");
                            System.out.println("\t\t9 退出系统");
                            System.out.print("请输入你的选择: ");
                            key = Utility.readString(1);
                            switch (key) {
                                case "1":
                                    System.out.println("显示在线用户列表");
                                    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;
                            }
                        }
                    } else {
                        System.out.println("登录失败");
                    }
                    break;
                case "9":
                    System.out.println("退出系统");
                    loop = false;
                    break;
            }
        }
    }
}

1.2 用户登录2

客户端UserClientServer类
该类用于完成用户登录验证和用户注册等功能;

public class UserClientServer {

    private User u = new User();
    private Socket socket;

    public boolean checkUser(String userId, String password) {
        //创建一个user对象
        u.setUserId(userId);
        u.setPassword(password);
        boolean b = false;

        try {
            //连接到服务端
            socket = new Socket(InetAddress.getLocalHost(), 9999);
            //获取socket关联的对象输出流
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(u);

            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
            Message message = (Message) ois.readObject();
            if (message.getMessType().equals(MessageType.MESSAGE_LOGIN_SUCCEED)) {
                //启动线程,维护socket
                ClientConnectServerThread clientConnectServerThread = new ClientConnectServerThread(socket);
                clientConnectServerThread.start();
                //集合,管理线程
                ManageClientConnectServerThread.addClientConnectServerThread(userId, clientConnectServerThread);
                b = true;
            } else {
                //如果连接失败,关闭已开启的socket
                socket.close();
                System.out.println();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return b;
    }
}

客户端线程类

public class ClientConnectServerThread extends Thread {
    //socket属性
    private Socket socket;
    //构造器socket赋值
    public ClientConnectServerThread(Socket socket) {
        this.socket = socket;
    }
    //得到socket
    public Socket getSocket() {
        return socket;
    }

    @Override
    public void run() {
        while (true) {

            try {
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Message message = (Message) ois.readObject();
                //做其它的处理

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

客户端管理线程的类
多用户及时通信系统_第5张图片

1.3 用户登录3

  • qqserver.server包下
    服务端,QQServer类
public class QQServer {
    private ServerSocket ss = null;
    public QQServer() {
        //端口可以写在配置文件
        try {
            System.out.println("服务端在9999端口监听");
            ss = new ServerSocket(9999);
            while (true) {
                Socket socket = ss.accept();
                //读取User对象
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                //输出Message对象
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                User u = (User) ois.readObject();
                Message message = new Message();
                if ("100".equals(u.getUserId()) && "123456".equals(u.getPassword())) {
                    message.setMessType(MessageType.MESSAGE_LOGIN_SUCCEED);
                    oos.writeObject(message);
                    //登陆成功后,创建线程和客户端保持通信
                    ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, u.getUserId());
                    serverConnectClientThread.start();
                    //把该线程对象放入集合中管理
                    ManageClientThreads.addClientThread(u.getUserId(), serverConnectClientThread);
                } else {//登录失败
                    message.setMessType(MessageType.MESSAGE_LOGIN_FAIL);
                    oos.writeObject(message);
                    socket.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服务端线程类
多用户及时通信系统_第6张图片
ManageClientThreads管理线程类
多用户及时通信系统_第7张图片

  • qqframe包下
    QQFrame类中启动程序

让多个用户登陆服务端,不再是"100","123456"这一个用户
多用户及时通信系统_第8张图片
紧接着专门写一个方法验证用户名和密码
多用户及时通信系统_第9张图片
单点登录
在这里插入图片描述
多用户及时通信系统_第10张图片

2. 拉取在线用户

补充MessageType
多用户及时通信系统_第11张图片
在客户端UserClientServer类中定义请求在线用户列表方法,并对服务端发出请求
多用户及时通信系统_第12张图片
多用户及时通信系统_第13张图片
在客户端的线程类中等待服务端发送数据
多用户及时通信系统_第14张图片
服务端代码
获取在线用户列表,即要遍历ManageClientThreads类中的hm集合,将这段遍历集合的代码封装进ManageClientThreads类中的getOnlineUser()方法
多用户及时通信系统_第15张图片
在服务端的线程类中接收请求用户列表的消息请求,调用getOnlineUser()方法得到在线用户列表,通过socket将数据返回给客户端
多用户及时通信系统_第16张图片

3. 无异常退出

多用户及时通信系统_第17张图片
在UserClientServer类中编写一个方法,客户端退出系统,并给服务器发送一个退出系统的message
多用户及时通信系统_第18张图片
在服务端响应客户端的请求,接收客户端发送的message,进行处理
多用户及时通信系统_第19张图片

4. 私聊系统

多用户及时通信系统_第20张图片

  • 客户端server包下新建MessageClientServer类
    该类用于提供和消息相关的服务方法
    在MessageClientServer类中编写一个方法并调用
    多用户及时通信系统_第21张图片
    多用户及时通信系统_第22张图片

在服务端的通信线程中接收这个message并进行转发
多用户及时通信系统_第23张图片
在客户端把从服务端转发过来的消息显示
多用户及时通信系统_第24张图片

5. 群聊

在客户端MessageClientServer类中编写一个方法,并调用;向服务端发送一个请求
多用户及时通信系统_第25张图片
多用户及时通信系统_第26张图片
在服务端的通信线程中接收这个message并进行转发(群发)
多用户及时通信系统_第27张图片
在客户端把从服务端转发过来的消息显示
在这里插入图片描述

3. 发送文件

多用户及时通信系统_第28张图片
补充MessageType
多用户及时通信系统_第29张图片
Message类扩充
多用户及时通信系统_第30张图片

  • server包下新建FileClientServer类
    该类/对象 完成文件传输服务
public class FileClientServer {
    /**
     * @param src 源文件
     * @param dest 把该文件传输到对方的哪个目录
     * @param sender 发送用户id
     * @param getter 接受用户id
     */
    public void sendFileToOne(String src, String dest, String sender, String getter) {
        //读取src文件 封装到message对象
        Message message = new Message();
        message.setMessType(MessageType.MESSAGE_FILE_MES);
        message.setSender(sender);
        message.setGetter(getter);
        message.setSrcPath(src);
        message.setDestPath(dest);
        //需要将文件读取
        BufferedInputStream bis = null;
        byte[] fileBytes = new byte[(int) new File(src).length()];//获取文件的大小(Long 字节)

        try {
            bis = new BufferedInputStream(new FileInputStream(src));
            bis.read(fileBytes);
            //将文件对应的字节数组设置到message对象
            message.setFileBytes(fileBytes);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //提示信息
        System.out.println("\n" + sender + "给 " + getter + " 发送文件:" +
                src + " 到对方的电脑目录" + dest);

        try {
            //发送
            ClientConnectServerThread clientConnectServerThread
                    = ManageClientConnectServerThread.getClientConnectServerThread(sender);
            Socket socket = clientConnectServerThread.getSocket();
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服务端接收这个消息并转发
多用户及时通信系统_第31张图片
客户端接收到转发消息,输出到控制台
多用户及时通信系统_第32张图片
客户端调用
多用户及时通信系统_第33张图片

3.1 服务端推送新闻

  • qqserver包下新建SendNewsToAllServer类
public class SendNewsToAllServer implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.print("请输入服务器要推送的新闻[exit退出推送新闻的线程]: ");
            String news = Utility.readString(1000);
            //构建一个消息
            Message message = new Message();
            message.setSender("服务器");
            message.setContent(news);
            message.setMessType(MessageType.MESSAGE_TO_ALL_MES);
            message.setSendTime(new Date().toString());
            System.out.println("服务器推送消息给所有人 说: " + news);

            //遍历当前所有的通信线程,得到Socket,并发送message
            Map<String, ServerConnectClientThread> hm = ManageClientThreads.getHm();

            Collection<ServerConnectClientThread> serverConnectClientThreads
                    = hm.values();
            Iterator<ServerConnectClientThread> iterator =
                    serverConnectClientThreads.iterator();
            while (iterator.hasNext()) {
                ServerConnectClientThread serverConnectClientThread = iterator.next();
                Socket socket = serverConnectClientThread.getSocket();
                try {
                    ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
                    oos.writeObject(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在QQServer类启动线程
多用户及时通信系统_第34张图片

3.2 离线留言和离线发文件

  1. 在ManageOffLIneUserMessage类中把添加离线消息这一功能进行封装
    多用户及时通信系统_第35张图片
    群聊消息
    当用户向所有的用户发送群聊消息的时候,给离线状态的用户设置留言
    多用户及时通信系统_第36张图片
    私聊消息
    当用户向某一离线用户发送私聊消息的时候,给这个离线用户设置留言
    多用户及时通信系统_第37张图片
    离线文件
    当用户向某一离线用户发送文件的时候,将文件暂存在服务端中,当用户上线时,得到message
    多用户及时通信系统_第38张图片
  2. 当离线用户登录的时候,登录成功后,服务器统一将离线消息(群聊和私聊)和离线文件发送给用户,将这一功能封装进ManageOffLIneUserMessage类
    多用户及时通信系统_第39张图片

你可能感兴趣的:(笔记,java,c#,开发语言)