JAVA实现的简单聊天室

项目名称

利用TCP协议,做一个带有登录,注册的无界面,控制版的多人聊天室。

使用到的知识点

循环,判断,集合,IO,多线程,网络编程等

准备工作

在当前模块下新建txt文件,文件中保存正确的用户名和密码

文件内容如下:

//左边是用户名
//右边是密码
zhangsan=123
lisi=1234
wangwu=12345

需求描述

① 客户端启动之后,需要连接服务端,并出现以下提示:

服务器已经连接成功
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:

②选择登录之后,出现以下提示:

服务器已经连接成功
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:
1
请输入用户名

③需要输入用户名和密码,输入完毕,没有按回车时,效果如下:

服务器已经连接成功
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:
1
请输入用户名
zhangsan
请输入密码
123

④按下回车,提交给服务器验证

服务器会结合txt文件中的用户名和密码进行判断

根据不同情况,服务器回写三种判断提示:

服务器回写第一种提示:登录成功
服务器回写第二种提示:密码有误  
服务器回写第三种提示:用户名不存在

⑤客户端接收服务端回写的数据,根据三种情况进行不同的处理方案

登录成功的情况, 可以开始聊天,出现以下提示:

服务器已经连接成功
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:
1
请输入用户名
zhangsan
请输入密码
123
1
登录成功,开始聊天
请输入您要说的话

密码错误的情况,需要重新输入,出现以下提示:

服务器已经连接成功
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:
1
请输入用户名
zhangsan
请输入密码
aaa
密码输入错误
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:

用户名不存在的情况,需要重新输入,出现以下提示:

服务器已经连接成功
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:
1
请输入用户名
zhaoliu
请输入密码
123456
用户名不存在
==============欢迎来到黑马聊天室================
1登录
2注册
请输入您的选择:

⑥如果成功登录,就可以开始聊天,此时的聊天是群聊,一个人发消息给服务端,服务端接收到之后需要群发给所有人

提示:

此时不能用广播地址,因为广播是UDP独有的

服务端可以将所有用户的Socket对象存储到一个集合中

当需要群发消息时,可以遍历集合发给所有的用户

此时的服务端,相当于做了一个消息的转发

转发核心思想如下图所示:

其他要求:

用户名和密码要求:

要求1:用户名要唯一,长度:6~18位,纯字母,不能有数字或其他符号。

要求2:密码长度3~8位。第一位必须是小写或者大小的字母,后面必须是纯数字。

客户端:

拥有登录、注册、聊天功能。

① 当客户端启动之后,要求让用户选择是登录操作还是注册操作,需要循环。

  • 如果是登录操作,就输入用户名和密码,以下面的格式发送给服务端

    username=zhangsan&password=123
  • 如果是注册操作,就输入用户名和密码,以下面的格式发送给服务端

    username=zhangsan&password=123

② 登录成功之后,直接开始聊天。

服务端:

① 先读取本地文件中所有的正确用户信息。

② 当有客户端来链接的时候,就开启一条线程。

③ 在线程里面判断当前用户是登录操作还是注册操作。

④ 登录,校验用户名和密码是否正确

⑤ 注册,校验用户名是否唯一,校验用户名和密码的格式是否正确

⑥ 如果登录成功,开始聊天

⑦ 如果注册成功,将用户信息写到本地,开始聊天

代码

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;


public class Client {
    public static void main(String[] args) throws IOException {
        //创建客服端对象,连接服务器
        Socket socket = new Socket("127.0.0.1", 10000);
        System.out.println("服务器已经连接成功");

        while (true) {
            System.out.println("==============欢迎来到黑马聊天室================");
            System.out.println("1登录");
            System.out.println("2注册");
            System.out.println("请输入您的选择:");
            Scanner sc = new Scanner(System.in);
            String choose = sc.nextLine();
            switch (choose) {
                case "1" -> login(socket);
                case "2" -> System.out.println("用户选择了注册");
                default -> System.out.println("没有这个选项");
            }
        }
    }

    private static void login(Socket socket) throws IOException {
        //向服务器写出数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        //键盘录入
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名");
        String username = sc.nextLine();
        System.out.println("请输入密码");
        String password = sc.nextLine();
        //拼接
        StringBuilder sb = new StringBuilder();
        //username=zhangsan&password=123
        sb.append("username=").append(username).append("&password=").append(password);
        //第一次写的是执行登录操作
        method(bw, "login");

        //第二次写的是用户名和密码的信息
        //往服务器写出用户名和密码
        method(bw, sb.toString());

        //接受服务器反馈的信息
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String message = br.readLine();
        //状态码 1:登录成功 2:用户名不存在 3:密码错误
        if ("1".equals(message)) {
            System.out.println("登录成功,开始聊天");

            //开始聊天的时候,服务器可能会向客服端发信息
            //开一条单独的线程,专门负责接受服务器发来的信息
            ClientThread t = new ClientThread(socket);
            t.start();
            //开始聊天
            talkAll2(bw);
        } else if ("3".equals(message)) {
            System.out.println("用户名不存在");
        } else if ("2".equals(message)) {
            System.out.println("密码错误");
        }
    }

    //向服务器写出消息
    private static void talkAll2(BufferedWriter bw) throws IOException {
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入消息:");
            String str = sc.nextLine();
            ;
            method(bw, str);
        }
    }

    private static void method(BufferedWriter bw, String str) throws IOException {
        bw.write(str);
        bw.newLine();
        bw.flush();
    }
}

//接受服务器发来的群发消息
class ClientThread extends Thread {
    Socket socket;

    ClientThread(Socket socket) {
        this.socket = socket;
    }


    //接受服务器发来的消息
    @Override
    public void run() {
       // 循环重复的接受
        while (true) {
            try {
                //接受服务器发来的聊天记录
                InputStream is = socket.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String message = br.readLine();
                System.out.println(message);

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

    }
}



import java.io.*;
import java.net.Socket;
import java.util.Properties;

public class Mythread extends Thread {
    Socket socket;
    Properties p;

    public Mythread(Socket socket, Properties p) {
        this.socket = socket;
        this.p = p;
    }

    @Override
    public void run() {
        //读取客户端发送过来的数据(用户名和密码)
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (true) {
                String choose = br.readLine();
                switch (choose) {
                    case "login" -> login(br);
                    case "register" -> System.out.println("用户选择了注册操作");
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    //获取用户登录时,传递过来的信息。
    //并进行判断
    //读取客户端发送过来的数据(用户名和密码)
    public void login(BufferedReader br) throws IOException {
        System.out.println("用户选择了登录操作");
        String userinfo = br.readLine();
        //username=zhangsan&password=123
        //将用户名和密码进行拆分
        String[] arr = userinfo.split("&");
        String usernameInput = arr[0].split("=")[1];
        String passwordInput = arr[1].split("=")[1];
        System.out.println("用户输入的用户名为:" + usernameInput);
        System.out.println("用户输入的密码为:" + passwordInput);
        if (p.containsKey(usernameInput)) {
            //如果用户名存在,继续判断密码  //通过用户名获取密码(键获取值)
            String rightPassword = p.get(usernameInput) + "";
            if (rightPassword.equals(passwordInput)) {
                //提示用户登录成功,可以开始聊天
                writeMessage2Client("1");
                //群发
                //登录成功的时候就需要把客服端的Socket对象保存起来,方便后面给其他用户发送消息
                Server.list.add(socket);//类名直接调用集合,保存所有的用户对象,方便对每一个用户客服端群发
                //接受客户端发送过来的消息,并打印到控制台
                talkAll1(br, usernameInput);
            } else {
                //密码输入有误
                writeMessage2Client("2");
            }
        } else {
            //如果用户名不存在,直接回写
            writeMessage2Client("3");
        }
    }

    //读取客户端发送过来的消息,并打印到控制台
    private void talkAll1(BufferedReader br, String username) throws IOException {
        while (true) {
            String message = br.readLine();
            System.out.println(username + "发送的消息:" + message);

            //群发
            for (Socket s : Server.list) {
                //s代表每一个客服端的Socket连接对象
                writeMessage2Client(s, username + "发送的消息:" + message);
            }
        }

    }


    //作用:服务端将消息发送给所有用户的客服端(群发)
    public void writeMessage2Client(Socket s, String message) throws IOException {
        // 写出数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        bw.write(message);
        bw.newLine();
        bw.flush();
    }

    /*
    作用: 将服务器端的消息回写客户端
     */
    public void writeMessage2Client(String message) throws IOException {
        // 写出数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write(message);
        bw.newLine();
        bw.flush();
    }
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Properties;


public class Server {
    static ArrayList<Socket> list = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        //创建服务的对象,绑定端口号
        ServerSocket ss = new ServerSocket(10000);
        //1.读取本地文件里正确的用户名和密码
        Properties p = new Properties();
        FileInputStream fis = new FileInputStream("..\\WX\\.idea\\Server\\userinfo.txt");
        //把文件里的数据加载到p集合当中
        p.load(fis);
        fis.close();

        while (true) {
            //2.只要来了一个客户端,就开一条线程处理
            //等待客户端连接
            Socket socket = ss.accept();
            //读取客服端发送的数据
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("有客户端来链接");
            Mythread t = new Mythread(socket, p);
            t.start();

        }


    }
}

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值