设计C/S架构的IM通信软件(4)

在之前的基础上添加了自定义消息协定:消息头+消息内容

去实现用户的登录注册功能

具体代码如下:

Client类:

复制代码
public class MClient {
    public static void main(String[] args) throws IOException {
        new MClient().StartMClient();
    }
    public OutputStream os;
    public InputStream is;
    public void StartMClient() throws IOException {
        //创建客户端
        Socket socket = new Socket("127.0.0.1",9999);
        //获取输入输出流
        os = socket.getOutputStream();
        is = socket.getInputStream();
        //线程启动 不实时读取消息
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        //读消息头 同样分三种情况
                        int head = is.read();
                        switch(head){
                            case MessageType.LOGIN:
                                //根据读取的结果进行判断
                                int b = is.read();
                                if(b == MessageType.YES){
                                    System.out.println("登录成功");
                                }else{
                                    System.out.println("登录失败");
                                }
                                break;
                            case MessageType.CHAT:
                                break;
                            case MessageType.REGISTER:
                                break;
                        }
                        //读取消息
                        String msg = readMsg();
                        System.out.println(msg);//给消息打印出来
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }

                }
            }
        }).start();
        //传入账号密码的数据
        String username = "21", password = "20";
        os.write(pcm0204.server.MessageType.LOGIN);
        sendMsg(username + ":" + password);

        //发送消息
        while(true){
            Scanner scan = new Scanner(System.in);//获得键盘输入
            String line = scan.nextLine();
            sendMsg(line);
        }
    }
    //读取消息
    public String readMsg() throws IOException {
        byte[] b = new byte[1024];
        is.read(b);
        String msg = new String(b);
        return msg.trim();//去掉周围空白部分
    }
    //发送消息
    public void sendMsg(String msg) throws IOException {
        String str = msg + "\r\n";
        os.write(str.getBytes());
        os.flush();
    }
}

消息头的实现接口

复制代码
//信息头使用接口 登录 注册 私聊 广播 聊天 yes no
public interface MessageType {
    public static final byte LOGIN = 1;
    public static final byte REGISTER = 2;
    public static final byte PRIVATE = 3;
    public static final byte GROUP = 4;
    public static final byte CHAT = 5;
    public static final byte YES = 6;
    public static final byte NO = 7;

}

用户类:

复制代码
public class User {
    public String username;
    public String password;
    public Integer userID;
    public User(){

    }

    public User(String password, String username) {
        this.password = password;
        this.username = username;
    }

    public User(String password, String username, Integer userID) {
        this.password = password;
        this.username = username;
        this.userID = userID;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getUserID() {
        return userID;
    }

    public void setUserID(Integer userID) {
        this.userID = userID;
    }
}

Server类:

复制代码
public class MServer {
    public static void main(String[] args) throws IOException {
        new MServer().StartMServer();
    }
    public Map<Integer,Socket> map;
    public int UserID;
    public List<User> userList = new ArrayList<>();
    //构筑方法初始化注册账号
    public MServer(){
        //先注册五个账号
        for(int i = 1; i <= 5; i++){
            userList.add(new User(i + "1" , i + "1"));
        }
    }
    public void StartMServer() throws IOException {
        //创建服务端
        ServerSocket server = new ServerSocket(9999);
        Map<Integer,Socket> map = new HashMap<>();
        int UserID = 1;
        //得用while true去实现
        while(true) {
            //去连接客户端
            Socket socket = server.accept();
            //把客户端放到map中
            map.put(UserID, socket);
            //创建线程 启动
            ServerThread serverThread = new ServerThread(socket, map, UserID++,userList);
            new Thread(serverThread).start();
        }
    }
}

ServerThread类:

复制代码
public class ServerThread implements Runnable{
    public Socket socket;
    public InputStream is;
    public OutputStream os;
    public int UserID;
    public Map<Integer,Socket> map;
    public List<User> userList;
    public ServerThread(Socket socket,Map<Integer,Socket> map,int UserID,List<User> userList){
        this.socket = socket;
        this.map = map;
        this.UserID = UserID;
        this.userList = userList;
        try {
            os = socket.getOutputStream();
            is = socket.getInputStream();
            sendMsg(UserID, os,"客户端连接成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    //自定义消息协议: 消息头+消息内容
    public void run() {
        while(true){
            try {
                //读取消息头
                int head = is.read();
                String msg = readMsg();
                switch(head){
                    //先分三种情况 登录 注册 私聊
                    case MessageType.LOGIN:
                        handleLogin(msg);
                        break;
                    case MessageType.REGISTER:
                        break;
                    case MessageType.CHAT:
                        String[] msgArr = msg.split(":");
                        if(msgArr[0].equals("g")){
                            //群发 不发送自己
                            for(Map.Entry<Integer,Socket> entry : map.entrySet()){
                                Socket s = entry.getValue();
                                if(s != socket){
                                    OutputStream output = s.getOutputStream();
                                    sendMsg(UserID,output,msg);
                                }
                            }
                        }else{
                            //指定用户私聊
                            Integer UserId = Integer.parseInt(msgArr[0]);
                            //根据id找到私聊对象
                            Socket s = map.get(UserId);
                            OutputStream output = s.getOutputStream();
                            //发送的内容是msgArr[1]
                            sendMsg(UserID,output,msgArr[1]);
                        }
                        System.out.println("Client : " + msg);
                        break;
                }

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    //处理登录请求的 String msg 存的是 账号和密码两部分 同样用:分割
    public void handleLogin(String msg) throws IOException {
        //分割消息
        String[] msgArr = msg.split(":");
        //遍历用户列表
        for(User user : userList){
            if(user.getUsername().equals(msgArr[0]) && user.getPassword().equals(msgArr[1])){
                //返回登录成功的消息
                os.write(MessageType.LOGIN);
                os.write(MessageType.YES);
                return;
            }
        }
        //返回登录失败的消息
        os.write(MessageType.LOGIN);
        os.write(MessageType.NO);
    }
    //读取消息
    public String readMsg() throws IOException {
        byte[] b = new byte[1024];
        is.read(b);
        String msg = new String(b);
        return msg.trim();//去掉周围空白部分
    }
    //发送消息
    public void sendMsg(int UserID, OutputStream os, String msg) throws IOException {//确保os是输出流
        String str = UserID + ":" + msg + "\r\n";
        os.write(str.getBytes());
        os.flush();
    }
}

具体的文件打包 如下实现:

相关推荐
代码无bug抓狂人2 小时前
C语言之表达式括号匹配
c语言·开发语言·算法
带刺的坐椅2 小时前
用 10 行 Java8 代码,开发一个自己的 ClaudeCodeCLI?你信吗?
java·ai·llm·agent·solon·mcp·claudecode·skills
Nebula_g2 小时前
线程进阶: 无人机自动防空平台开发教程(更新)
java·开发语言·数据结构·学习·算法·无人机
HAPPY酷2 小时前
构造与析构:C++ 中对象的温柔生灭
java·jvm·c++
lang201509282 小时前
Java JSR 250核心注解全解析
java·开发语言
齐鲁大虾3 小时前
Linux下用什么编程语言方便开发B/S架构程序
linux·运维·架构
czhc11400756633 小时前
协议 25
java·开发语言·算法
逆光的July3 小时前
如何解决超卖问题
java
Volunteer Technology3 小时前
MinIo介绍和使用
架构