java多人聊天室

目录

多人聊天室需求分析

服务器

客户端

数据存储Arraylist数组类

用户类

线程类

服务器线程

客户端读取线程

客户端写入线程

关流工具类


多人聊天室需求分析


服务器

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("聊天室创建成功");
        Socket accept;
        ServerThread thread;
        while (true){
            //接收套接字
            accept = serverSocket.accept();
            //服务器线程
            thread = new ServerThread(accept);
            thread.start();
            //线程启动,将线程加入集合
            ArrayListDB.list.add(thread);
        }
    }
}

客户端

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);
        new ReaderThread(socket).start();
        new WriteThread(socket).start();
    }
}

数据存储Arraylist数组类

public class ArrayListDB {
    public static ArrayList<ServerThread> list = new ArrayList<>();
}

用户类

public class User {
    private String name;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

线程类

服务器线程

public class ServerThread extends Thread {
    private Socket socket;
    private User user;
    //读取客户端发送的消息再发送给其他用户
    private BufferedReader br;
    private BufferedWriter bw;

    public ServerThread(Socket socket) throws IOException {
        this.socket = socket;
        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //避免空指针异常
        user = new User("1");
    }

    //拿到User对象
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public void run() {
        try {
            //用户注册----第一次客户端发送过来的数据
            register();
            //消息转发
            forword();
        } catch (IOException e) {
            //客户端强制关闭,没有通过esc关闭
            offline();
        } finally {
            IOUtils.closeAll(br, bw, socket);
        }
    }
    //转发消息
    private void forword() throws IOException {
        //获取用户输入的消息
        String str = "";
        while (true) {
            //1.获取用户输入的数据
            str = br.readLine();
            //2.判断是否为退出指令
            if ("esc".equalsIgnoreCase(str)) {
                //下线
                offline();
                //将esc发送给所有客户端,告诉客户端服务器下线了
                send("esc");
                break;
            }
            //3.判断是否为私聊
            if(str.startsWith("@")){
                oneByone(str);
                continue;
            }
            //4.群聊
            sendToOther(user.getName()+":"+str);
        }
    }
    //私聊-----str   私聊的消息
    private void oneByone(String str) throws IOException {
        //使用正则表达式判断是否符合私聊规则--规则:@+2-8个字符的名字+英文:或中文:
        boolean flag = str.matches("[@].{2,8}[::].+");
        if(!flag){
            send("系统:如需私聊,请符合格式,@某某某:....");
            //结束方法,重新输入
            return;
        }
        //获取对方名字
        String receiveName = str.split("[::]")[0].substring(1);
        //检查是否有此名字,调用方法检查名字是否存在
        flag = chackname(receiveName);
        if(flag){
            send("系统:私聊用户不存在或用户已下线,请重新输入");
            return;
        }
        //获取私聊内容
        str = str.substring(receiveName.length()+2);
        //发消息给指定的人
        sendToOne(receiveName,str);
    }
    /**
     * 发送私聊消息
     * @param receiveName   接收方的名字
     * @param str            私聊内容
     */
    private void sendToOne(String receiveName, String str) throws IOException {
        //遍历集合
        for (ServerThread s:ArrayListDB.list) {
            //找到私聊对象
            if(s.getUser().getName().equals(receiveName)){
                s.send(this.getUser().getName()+"私聊:"+str);
            }
        }
    }

    //下线方法
    private void offline() {
        //告诉当前客户端你已经退出
        try {
            send("系统:你已退出聊天室");
            //通知其他用户
            sendToOther("系统:" + user.getName() + "已退出聊天室");
        } catch (IOException e) {
            try {
                //通知其他用户当前用户退出聊天室
                sendToOther("系统:" + user.getName() + "已退出聊天室");
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }finally {
            //把集合中服务器的线程清理掉
            ArrayListDB.list.remove(this);
        }
    }

    //用户注册
    private void register() throws IOException {
        String name = "";
        boolean flag = false;
        do {
            //读取客户端发送的名字
            name = br.readLine();
            //判断名字是否重复
            flag = chackname(name);
            //提示用户重新输入
            if (!flag) {
                send("系统:用户名已存在,请重新输入");
                continue;
            }
            //判断用户名长度是否合理
            flag = chackLength(name);
            if (!flag) {
                send("系统:用户名长度不合理,请输入2-8个字符");
                continue;
            }
            //判断用户名是否为敏感词
            if ("系统".equals(name)) {
                send("系统:不能以“系统”当做用户名,请重新输入");
                continue;
            }
            //用户名合理,保存用户名
            this.user.setName(name);
            //通知当前用户注册用户注册成功
            send("系统:恭喜" + name + "这个名字注册成功,欢迎进入Java交流群");
            //通知当前连接上系统的其他用户
            sendToOther("系统:" + name + "进入Java交流群");
            break;
        } while (true);

    }

    //发送给其他人
    private void sendToOther(String str) throws IOException {
        for (ServerThread s : ArrayListDB.list) {
            //如果是自己就不发送
            if (s != this&& !"1".equals(s.getUser().getName())) {
                s.send(str);
            }
        }
    }

    //判断用户名长度方法
    private boolean chackLength(String name) {
        //避免空指针异常
        if (name != null) {
            if (name.length() >= 2 && name.length() <= 8) {
                return true;
            }
        }
        return false;
    }

    //发送给客户端的方法
    private void send(String s) throws IOException {
        bw.write(s);
        bw.newLine();
        bw.flush();
    }

    //判断名字是否重复的方法
    /**
     *  判断用户名是否重复
     * @param name  用户名
     * @return  重复返回false
     */
    private boolean chackname(String name) {
        for (ServerThread t : ArrayListDB.list) {
            if (t.getUser().getName().equals(name)) {
                return false;
            }
        }
        return true;
    }
}

客户端读取线程

public class ReaderThread extends Thread{
    private BufferedReader br;
    private Socket socket;
    //读取线程构造方法,传入套接字
    public ReaderThread(Socket socket) throws IOException {
        this.socket = socket;
        //获取输入流
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }
    @Override
    public void run() {
        try{
            String str = "";
            while (true){
                str = br.readLine();
                if("esc".equalsIgnoreCase(str)){
                    //如果输入esc,停机
                    System.exit(0);
                }else {
                    System.out.println(str);
                }
            }
        } catch (IOException e) {
            System.out.println("系统:服务器已关闭");
            System.exit(0);
        }finally {
            IOUtils.closeAll(br,socket);
        }

    }
}

客户端写入线程

//客户端写线程
public class WriteThread extends Thread{
    private Socket socket;
    private BufferedReader br;
    private BufferedWriter bw;
    //创建写线程构造方法,需传入套接字
    public WriteThread(Socket socket) throws IOException {
        this.socket = socket;
        //创建输入流获取控制台录入的信息,存入缓冲区
        br = new BufferedReader(new InputStreamReader(System.in));
        //创建输出流
        bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    }
    @Override
    public void run() {
        try{
            System.out.println("系统:请输入名字进行注册");
            String str = "";
            while (true){
                str = br.readLine();
                if(str != null){
                    //先写出去
                    bw.write(str);
                    bw.newLine();
                    bw.flush();
                    //如果是esc则停机
                    if("esc".equalsIgnoreCase(str)){
                        System.exit(0);
                    }
                }
            }
        } catch (IOException e) {
            System.out.println("客户端读取异常");
            e.printStackTrace();
        }finally {
            IOUtils.closeAll(bw,br,socket);
        }
    }
}

关流工具类

public class IOUtils {
    public static void closeAll(Closeable... closeables){
        for (Closeable c:closeables) {
            if(c != null){
                try {
                    c.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ayou2020

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

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

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

打赏作者

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

抵扣说明:

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

余额充值