Java基础小练习-控制台聊天室

知识储备

  • 面向对象
  • IO
  • 异常处理
  • 多线程
  • 网络编程

实现功能

  • 基础群聊功能
  • 私聊功能
  • 新加入用户实时通知
  • 用户控制台关闭(用户退出)实时通知

代码实现

Constant.java

/**
 * 常量维护工具类
 * @author Blank
 */
public class Constant {
    
    
    private Constant() {
    
    }
    // 服务器地址
    public final static String SERVER_HOST = "localhost";
    // 服务器端口
    public final static int SERVER_PORT = 6666;
}

CloseUtil.java

import java.io.Closeable;
import java.io.IOException;

/**
 * 关闭资源工具类
 * @author Blank
 */
public class CloseUtil {
    
    
    private CloseUtil() {
    
    }

    /**
     * 关闭已打开的资源
     * @param targets
     */
    public static void close(Closeable... targets) {
    
    
        try {
    
    
            for (Closeable target : targets) {
    
    
                if (target != null) {
    
    
                    target.close();
                }
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

UserSend.java

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 用户发送线程
 * @author Blank
 */
public class UserSend extends Thread {
    
    
    // 线程运行标志
    private boolean isRunning;
    // 数据输出流
    private DataOutputStream dos;
    // 控制台输入
    private BufferedReader console;

    /**
     * 构造器初始化要使用的资源
     * @param client
     */
    public UserSend(Socket client) {
    
    
        isRunning = true;
        console = new BufferedReader(new InputStreamReader(System.in));
        try {
    
    
            dos = new DataOutputStream(client.getOutputStream());
        } catch (IOException e) {
    
    
            isRunning = false;
            CloseUtil.close(console);
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
    
    
        // 运行时循环读取消息并发送
        while (isRunning) {
    
    
            sendMessage(getMsgFromConsole());
        }
    }

    /**
     * 从控制台读取消息
     * @return 消息内容
     */
    private String getMsgFromConsole() {
    
    
        String messge = "";
        try {
    
    
            messge = console.readLine();
        } catch (IOException e) {
    
    
            isRunning = false;
            CloseUtil.close(console,dos);
            e.printStackTrace();
        }
        return messge;
    }

    /**
     * 发送消息
     * @param message
     */
    private void sendMessage(String message) {
    
    
        try {
    
    
            dos.writeUTF(message);
            dos.flush();
        } catch (IOException e) {
    
    
            isRunning = false;
            CloseUtil.close(console,dos);
            e.printStackTrace();
        }
    }
}

UserReceive.java

import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;

/**
 * 用户接收线程
 * @author Blank
 */
public class UserReceive extends Thread {
    
    
    // 线程运行标志
    private boolean isRunning;
    // 数据输入流
    private DataInputStream dis;

    /**
     * 构造器初始化要使用的资源
     * @param client
     */
    public UserReceive(Socket client) {
    
    
        isRunning = true;
        try {
    
    
            dis = new DataInputStream(client.getInputStream());
        } catch (IOException e) {
    
    
            isRunning = false;
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
    
    
        // 运行时循环从服务器读取并输出
        while (isRunning) {
    
    
            getAndOutputMessage();
        }
    }

    /**
     * 获取消息并输出
     */
    private void getAndOutputMessage() {
    
    
        try {
    
    
            String message = dis.readUTF();
            System.out.println(message);
        } catch (IOException e) {
    
    
            isRunning = false;
            CloseUtil.close(dis);
            e.printStackTrace();
        }
    }

}

User.java

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Map;
import java.util.Set;

public class User extends Thread {
    
    
    // 线程运行标志
    private boolean isRunning;
    // 数据输入流
    private DataInputStream dis;
    // 数据输出流
    private DataOutputStream dos;

    public User(Socket client) {
    
    
        isRunning = true;
        try {
    
    
            dis = new DataInputStream(client.getInputStream());
            dos = new DataOutputStream(client.getOutputStream());
            init();
        } catch (IOException e) {
    
    
            isRunning = false;
            CloseUtil.close(dis);
            e.printStackTrace();
        }
    }

    /**
     * 初始化 输入用户名
     */
    private void init() throws IOException {
    
    
        while (true) {
    
    
            dos.writeUTF("******请输入用户名******");
            dos.flush();
            String name = dis.readUTF().trim();
            if (name.length() == 0) {
    
    
                dos.writeUTF("******警告:用户名不能为空!******");
                dos.flush();
            }else {
    
    
                this.setName(name);
                dos.writeUTF( "******欢迎您! " + name + "******");
                dos.flush();
                messageTrans("用户" + name + "加入了群聊!",true);
                break;
            }
        }
    }

    @Override
    public void run() {
    
    
        // 线程运行时转发消息
        while (isRunning) {
    
    
            try {
    
    
                String message = getMessage();
                if (message.length() > 0)
                    messageTrans(message,false);
            } catch (IOException e) {
    
    
                isRunning = false;
                CloseUtil.close(dis,dos);
                ChatServer.users.remove(this.getName());
                try {
    
    
                    messageTrans("用户" + this.getName() + "退出群聊!",true);
                } catch (IOException ex) {
    
    
                    ex.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取消息
     * @return
     */
    private String getMessage() throws IOException {
    
    
        String message = dis.readUTF().trim();
        return message;
    }

    /**
     * 消息转发 约定私聊格式 @name:message
     * @param message
     * @param isSys
     * @throws IOException
     */
    private void messageTrans(String message,boolean isSys) throws IOException {
    
    
        if (isSys) {
    
    
            message = "******系统消息:" + message + "******";
            broadcast(message);
        }else {
    
    
            if (message.startsWith("@")) {
    
    
                if (message.contains(":")) {
    
    
                    // 私聊
                    int i = message.indexOf(":");
                    String name = message.substring(1,i);
                    if (name.equals(this.getName())) {
    
    
                        // 不能私聊自己
                        dos.writeUTF("******警告:不能私聊自己!******");
                        dos.flush();
                    }else {
    
    
                        message = message.substring(i+1);
                        if (ChatServer.users.containsKey(name)) {
    
    
                            User user = ChatServer.users.get(name);
                            user.dos.writeUTF(this.getName() + "悄悄对你说: " + message);
                            user.dos.flush();
                        }else {
    
    
                            // 无此用户
                            dos.writeUTF("******警告:您私聊的用户不存在!******");
                            dos.flush();
                        }
                    }
                }else {
    
    
                    // 私聊格式不正确
                    dos.writeUTF("******警告:您私聊的格式不正确!******");
                    dos.flush();
                }
            }else {
    
    
                // 正常群聊
                message = this.getName() + ": " + message;
                broadcast(message);
            }
        }
    }

    /**
     * 广播消息
     * @param message
     * @throws IOException
     */
    private void broadcast(String message) throws IOException {
    
    
        Set<Map.Entry<String, User>> users = ChatServer.users.entrySet();
        for (Map.Entry<String, User> user : users) {
    
    
            if (user.getKey().equals(this.getName())) continue;
            DataOutputStream dos = user.getValue().dos;
            dos.writeUTF(message);
            dos.flush();
        }
    }
}

ChatServer.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * 聊天服务端
 * @author Blank
 */
public class ChatServer {
    
    
    // 用户统一存储
    public static Map<String,User> users = new HashMap<>();

    public static void main(String[] args) throws IOException {
    
    
        ServerSocket server = new ServerSocket(Constant.SERVER_PORT);
        System.out.println("服务器已启动!");
        while (true) {
    
    
            Socket client = server.accept();
            new Thread(()->{
    
    
                User user = new User(client);
                users.put(user.getName(),user);
                user.start();
            }).start();
        }
    }
}

ChatClient.java

import java.io.IOException;
import java.net.Socket;

/**
 * 聊天客户端
 * @author Blank
 */
public class ChatClient {
    
    
    public static void main(String[] args) throws IOException {
    
    
        Socket client = new Socket(Constant.SERVER_HOST,Constant.SERVER_PORT);
        new UserSend(client).start();
        new UserReceive(client).start();
    }
}

猜你喜欢

转载自blog.csdn.net/L333333333/article/details/104314964