Java-多用户即时通信系统-用户登录(客户端)

Java-多用户即时通信系统-用户登录(客户端)

  • 根据前面的需求分析,实现客户端用户登录功能;

1 实体类(放在common包下)

  • 包括用户类(User)、消息类(Message)、消息类型接口(MessageType)

User

  • 用户类
/**
 * @author: SEA
 * @date: 2023/5/4
 */
public class User implements Serializable {
    private static final long serialVersionUID = 1L;//序列化ID,用来保证序列化和反序列化过程中,User类的一致性
    private String userID;//用户名
    private String password;//密码
    public User() {
    }

    public User(String userID, String password) {
        this.userID = userID;
        this.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;
    }

    @Override
    public String toString() {
        return "User{" +
                "userID='" + userID + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

Message

  • 消息类
/**
 * @author: SEA
 * @date: 2023/5/4
 */
public class Message implements Serializable {
    private static final long serialVersionUID = 1L;//序列化ID,用来保证序列化和反序列化过程中,User类的一致性
    private String sender_ip;//发送方ip
    private String receiver_ip;//接收方ip
    private String send_data;//发送内容
    private String send_time;//发送时间
    private String message_type;//消息类型(如:文本,图片,音频,视频等)

    public Message() {
    }

    public Message(String sender_ip, String receiver_ip, String send_data, String send_time, String message_type) {
        this.sender_ip = sender_ip;
        this.receiver_ip = receiver_ip;
        this.send_data = send_data;
        this.send_time = send_time;
        this.message_type = message_type;
    }

    public String getSender_ip() {
        return sender_ip;
    }

    public void setSender_ip(String sender_ip) {
        this.sender_ip = sender_ip;
    }

    public String getReceiver_ip() {
        return receiver_ip;
    }

    public void setReceiver_ip(String receiver_ip) {
        this.receiver_ip = receiver_ip;
    }

    public String getSend_data() {
        return send_data;
    }

    public void setSend_data(String send_data) {
        this.send_data = send_data;
    }

    public String getSend_time() {
        return send_time;
    }

    public void setSend_time(String send_time) {
        this.send_time = send_time;
    }

    public String getMessage_type() {
        return message_type;
    }

    public void setMessage_type(String message_type) {
        this.message_type = message_type;
    }
}

MessageType

  • 消息类型接口
/**
 * @author: sea-365
 * @date: 2023/5/4 20:54
 */
public interface MessageType {
    String MESSAGE_LOGIN_SUCCEED = "1";//表示登录成功
    String MESSAGE_LOGIN_FAILED = "1";//表示登录成功
}

2 功能类(放在service包下)

UserClientService

  • 实现用户登录、注册等功能的类;
/**
 * 该类完成用户登录验证,用户注册等功能
 * @author: SEA
 * @date: 2023/5/5
 */
public class UserClientService {
    User user = new User();//User对象
    Socket socket = null;//Socket对象


    /**
     * 用户登录验证
     * @param userID 用户名
     * @param password 密码
     * @return 返回登录验证结果
     */
    public boolean checkUser(String userID, String password) throws IOException, ClassNotFoundException {

        user.setuserID(userID);
        user.setPassword(password);

        //向服务器发送User对象,根据服务器返回的结果进行验证
        socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        //发送user对象
        objectOutputStream.writeObject(user);

        //socket.shutdownOutput();

        //读取服务器端返回的验证结果
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
        //读取返回的Message对象
        Message message = (Message) objectInputStream.readObject();

        if(message.getMessage_type().equals(MessageType.MESSAGE_LOGIN_SUCCEED)) {//登录成功
            //登录成功,创建一个与服务器端保持通信的线程 -> 创建一个线程类ClientConnectServerThread
            ClientConnectServerThread clientConnectServerThread = new ClientConnectServerThread();
            //启动客户端与服务器端通信的线程
            clientConnectServerThread.start();
            //为了方便拓展,将该线程放在一个集合中进行管理
            //【关于“拓展”】:比如,客户端在私聊另一个客户端的同时,还在与其他客户端发送文件,此时需要同时进行两个任务,使用多线程并发实现
            ClientConnectServerThreadManage.addClientConnectServerThread(userID, clientConnectServerThread);

            return true;
        }
        else {//登录失败
            //应该关闭打开的流 和 Socket对象
            objectInputStream.close();
            socket.close();
            return false;
        }
    }
}

ClientConnectServerThread

  • 客户端保持与服务器端通信的线程类
/**
 * 客户端保持与服务器端通信的线程
 * @author: SEA
 * @date: 2023/5/5
 */
public class ClientConnectServerThread extends Thread{
    //持有用于网络通信的Socket对象
    private Socket socket;

    public ClientConnectServerThread(){ }

    public ClientConnectServerThread(Socket socket){
        this.socket = socket;
    }

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //客户端需要在后台一直保持与服务器端通信,因此使用while循环;
        //【因此这种阻塞式IO的方式,导致效率比较低!】
        while(true){
            try {
                ObjectInputStream objectInputStream = new ObjectInputStream(this.getSocket().getInputStream());
                //读取服务器端发送的数据,如果没有发送数据,则线程阻塞!
                Message message = (Message) objectInputStream.readObject();
                System.out.println(" 处理服务器端发送的消息: " +message.getSend_data());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

ClientConnectServerThreadManage

  • 管理ClientConnectServerThread线程的类
/**
 * @author: SEA
 * @date: 2023/5/5
 */
public class ClientConnectServerThreadManage {
    //管理ClientConnectServerThread线程类的集合, 以userID为key;
    private static HashMap<String, ClientConnectServerThread> clientConnectServerThreads = new HashMap<>();

    public ClientConnectServerThreadManage() {
    }

    //向集合添加一个线程
    public static void addClientConnectServerThread(String userID, ClientConnectServerThread clientConnectServerThread){
        clientConnectServerThreads.put(userID, clientConnectServerThread);
    }

    //根据userID获取集合中的某个线程
    public static ClientConnectServerThread getClientConnectServerThread(String userID){
        return clientConnectServerThreads.get(userID);
    }
}

3 工具类(放在utils包下)

Util_KeyBoardInput

  • 用于处理用户键盘输入的工具类
/**
 * @author: SEA
 * @date: 2023/5/5
 */
public class Util_KeyBoardInput {
    //静态属性scanner
    private static Scanner scanner = new Scanner(System.in);

    /**
     * 读取键盘输入的指定长度的字符串(不能为空串,limit >= 1)
     * @param limit 限定的长度
     * @return 指定长度的字符串
     */
    public static String readString(int limit){
        return readKeyBoard(limit, false);
    }

    /**
     * 功能: 读取一个字符串
     * @param limit 读取的长度
     * @param blankReturn 如果为true ,表示 可以读空字符串。
     * 					  如果为false表示 不能读空字符串。
     *	如果输入为空,或者输入大于limit的长度,就会提示重新输入。
     * @return
     */
    private static String readKeyBoard(int limit, boolean blankReturn) {
        String line = "";
        while(scanner.hasNextLine()){
            line = scanner.nextLine();
            //如果line.length=0, 即用户没有输入任何内容,直接回车
            if (line.length() == 0) {
                if (blankReturn) return line;//如果blankReturn=true,可以返回空串
                else continue; //如果blankReturn=false,不接受空串,必须输入内容
            }

            //如果用户输入的内容大于了 limit,就提示重写输入
            //如果用户如的内容 >0 <= limit ,我就接受
            if (line.length() < 1 || line.length() > limit) {
                System.out.print("输入长度(不能大于" + limit + ")错误,请重新输入:");
                continue;
            }
            break;
        }
        return line;
    }
}

4 界面类(放在view包下)

QQClientView

  • 客户端界面类(目前没有前端,使用命令行输出的方式展示前端);
/**
 * @author: SEA
 * @date: 2023/5/5
 */
public class QQClientView {
    private boolean isLoop = true;//是否退出系统
    private String userID, password;//用户输入的登录信息
    private UserClientService userClientService = new UserClientService();//用于用户登录注册等功能的对象

    public void mainView() throws Exception {
        String selectItem;
        Scanner scanner = new Scanner(System.in);
        while(isLoop){
            System.out.println("=============== 欢迎登录网络通信系统 ===============");
            System.out.println("\t\t\t\t 1 登录系统 \t\t");
            System.out.println("\t\t\t\t 9 退出系统 \t\t");
            System.out.print("请输入您的选择:");
            selectItem = Util_KeyBoardInput.readString(1);
            switch (selectItem){
                case "1":
                    System.out.print("请输入用户名: ");
                    userID = Util_KeyBoardInput.readString(50);
                    System.out.print("请输入密  码:");
                    password = Util_KeyBoardInput.readString(50);
                    System.out.println("登录验证中......");
                    if(userClientService.checkUser(userID, password)){
                        System.out.println("=============== 欢迎您("+ userID +")登录网络通信系统 ===============");
                        //进入二级菜单
                        while(isLoop){
                            System.out.println("=============== 欢迎您("+ userID +"),这里是网络通信系统二级菜单 ===============");
                            System.out.println("\t\t\t\t 1 显示在线用户列表 \t\t");
                            System.out.println("\t\t\t\t 2 群发消息 \t\t");
                            System.out.println("\t\t\t\t 3 私聊消息 \t\t");
                            System.out.println("\t\t\t\t 4 发送文件 \t\t");
                            System.out.println("\t\t\t\t 9 退出系统 \t\t");
                            System.out.print("请输入您的选择:");
                            selectItem = Util_KeyBoardInput.readString(1);
                            switch (selectItem){
                                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":
                                    isLoop = false;
                                    break;
                                default:
                                    System.out.println("请输入正确的选项!");
                                    break;
                            }
                        }
                    }
                    else{
                        System.out.println("登录失败!请检查用户名和密码是否正确。");
                    }
                    break;
                case "9":
                    isLoop = false;
                    break;
                default:
                    System.out.println("请输入正确的选项!");
                    break;
            }
        }
    }

    public static void main(String[] args) {
        QQClientView qqView = new QQClientView();
        try {
            qqView.mainView();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,这是一个比较复杂的问题,我会尽力回答。首先,您需要了解以下几个概念: 1. Socket:Socket是Java中用于实现网络通信的API,它提供了一种机制,使得应用程序可以通过网络连接到另一个应用程序,并进行数据传输。 2. ServerSocket:ServerSocket是Socket的一种子类,用于在服务器端监听客户端的连接请求,并创建对应的Socket实例进行通信。 3. 线程:由于一个服务器需要同时处理多个客户端连接,因此我们需要使用多线程技术,每个客户端连接都会创建一个对应的线程进行处理。 有了这些基础知识,下面是一个简单的示例代码,可以实现一个基于Socket通信即时通信软件: ```java // 服务端代码 import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) { try { // 创建ServerSocket对象,监听指定的端口 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务器已启动,等待客户端连接..."); while (true) { // 等待客户端连接请求 Socket socket = serverSocket.accept(); System.out.println("客户端已连接:" + socket.getInetAddress().getHostAddress()); // 创建一个新线程进行处理 new ServerThread(socket).start(); } } catch (IOException e) { e.printStackTrace(); } } } // 服务端线程代码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class ServerThread extends Thread { private Socket socket; public ServerThread(Socket socket) { this.socket = socket; } @Override public void run() { try { // 获取输入输出流 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream()); // 循环读取客户端发送的消息 String message; while ((message = in.readLine()) != null) { System.out.println("收到客户端消息:" + message); // 将消息转发给所有客户端 for (Socket client : ServerManager.getInstance().getClients()) { PrintWriter clientOut = new PrintWriter(client.getOutputStream()); clientOut.println(message); clientOut.flush(); } } } catch (IOException e) { e.printStackTrace(); } finally { // 关闭连接 try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 客户端代码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class Client { public static void main(String[] args) { try { // 连接服务器 Socket socket = new Socket("localhost", 8888); System.out.println("已连接服务器:" + socket.getInetAddress().getHostAddress()); // 启动读取服务器消息的线程 new ClientThread(socket).start(); // 获取输入输出流 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(socket.getOutputStream()); // 循环读取用户输入的消息发送给服务器 String message; while ((message = in.readLine()) != null) { out.println(message); out.flush(); } } catch (IOException e) { e.printStackTrace(); } } } // 客户端线程代码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; public class ClientThread extends Thread { private Socket socket; public ClientThread(Socket socket) { this.socket = socket; } @Override public void run() { try { // 获取输入流,循环读取服务器发送的消息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String message; while ((message = in.readLine()) != null) { System.out.println("收到服务器消息:" + message); } } catch (IOException e) { e.printStackTrace(); } } } // 服务端管理类,用于管理所有客户端连接 import java.net.Socket; import java.util.ArrayList; import java.util.List; public class ServerManager { private static ServerManager instance = new ServerManager(); private List<Socket> clients = new ArrayList<>(); private ServerManager() {} public static ServerManager getInstance() { return instance; } public synchronized void addClient(Socket socket) { clients.add(socket); } public synchronized void removeClient(Socket socket) { clients.remove(socket); } public synchronized List<Socket> getClients() { return clients; } } ``` 以上代码中,Server类是服务器端的主类,它创建了一个ServerSocket对象,并在循环中等待客户端连接请求。每当有一个客户端连接成功后,会创建一个新的ServerThread线程进行处理,将客户端消息转发给所有连接的客户端。 Client类是客户端的主类,它创建了一个Socket对象,并启动一个ClientThread线程用于读取服务器发送的消息。在循环中读取用户输入的消息后,发送给服务器。 ServerThread和ClientThread都是继承自Thread类的线程类,它们通过Socket对象获取输入输出流,循环读取客户端或服务器发送的消息。 ServerManager是一个服务端管理类,用于管理所有客户端连接。它是一个单例类,在addClient方法中添加客户端连接,在removeClient方法中移除客户端连接,在getClients方法中获取所有客户端连接。 以上是一个简单的示例代码,可以实现基于Socket通信即时通信软件。但这只是一个简单的示例,实际应用中还需要考虑许多其他因素,如安全性、性能等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SEA-365

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值