Java-网络编程-基于Tcp协议的网络聊天室

项目名称:

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

知识点:

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

需求描述:

1.开始界面

==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:

登陆界面输入自己的选项进入下一步

 2.登陆界面

==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
1
请输入用户名:
zhangsan
请输入密码:
123

 向服务器发送用户数据进行判断。

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

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

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

    username=zhangsan&password=123

登陆成功,服务器会向客户端返回登陆成功的状态码

登陆失败,服务器则会向客户端返回用户名不存在或者密码错误的状态码

客户端会识别状态码并在控制台输出状态码的信息

①.登陆成功

连接服务端成功!
==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
1
请输入用户名:
zhangsan
请输入密码:
123
登陆成功!请开始聊天
请输入聊天内容:

②.用户名不存在

连接服务端成功!
==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
1
请输入用户名:
dasdadas
请输入密码:
123456
用户名不存在!

 ③.密码错误

==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
1
请输入用户名:
zhangsan
请输入密码:
56468
密码错误,登陆失败!

 3.注册界面

注册操作,客户端会先判断用户输入的用户名密码是否符合规范

用户名和密码要求:

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

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

利用正则表达式进行判断

符合规范则将数据传输给服务器进行用户名的唯一性判断

如果用户名是唯一的,则将用户信息利用io流写入服务器端的配置文件中,并更新配置文件

==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
2
您正在进行注册操作
请输入用户名:
zhangsangggg
请输入密码:
a12348

注册成功

用户名不唯一,服务器会向客户端返回 用户名存在

==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
2
您正在进行注册操作
请输入用户名:
zhangsan
请输入密码:
a123456
用户名存在,请重新操作!

 4.聊天界面

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

 将每个人发送向服务器的消息转发给所有的客户端

服务器转发的主要逻辑:

服务器判断用户登陆成功之后,立即将该用户的客户端与服务器通信的socket对象存储在一个static关键字修饰的Arraylist集合中,这样每个服务器线程都可以共享这个集合,可以从这个集合中获取每个连接上服务器的客户端的socket对象,并利用这些socket对象中的io流进行消息的转发

界面展示

wangwu用户登陆进行聊天

==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
1
请输入用户名:
wangwu
请输入密码:
123456789
登陆成功!请开始聊天
请输入聊天内容:
你好
请输入聊天内容:
wangwu:你好
lisi:wangwu你好
zhangsan:你们好
晚上一起去吃饭吗?
请输入聊天内容:
wangwu:晚上一起去吃饭吗?
lisi:好的,一起去吧
zhangsan:好的一起去吧 

 lisi用户登陆进行聊天

连接服务端成功!
==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
1
请输入用户名:
lisi
请输入密码:
1234
登陆成功!请开始聊天
请输入聊天内容:
wangwu:你好
wangwu你好
请输入聊天内容:
lisi:wangwu你好
zhangsan:你们好
wangwu:晚上一起去吃饭吗?
好的,一起去吧
请输入聊天内容:
lisi:好的,一起去吧
zhangsan:好的一起去吧 

zhangsan用户登陆进行聊天

连接服务端成功!
==============欢迎来到聊天室===============
1.登陆
2.注册
请输入您的选择:
1
请输入用户名:
zhangsan
请输入密码:
123
登陆成功!请开始聊天
请输入聊天内容:
wangwu:你好
lisi:wangwu你好
你们好
请输入聊天内容:
zhangsan:你们好
wangwu:晚上一起去吃饭吗?
lisi:好的,一起去吧
好的一起去吧
请输入聊天内容:
zhangsan:好的一起去吧 

服务器端主要逻辑

服务端:

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

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

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

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

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

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

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

 

主要代码:

 客户端:

import java.io.*;
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"-> register(socket);
                default -> System.out.println("没有这个选择");
            }

        }

    }
    //登陆操作
    public 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 name = sc.nextLine();
        System.out.println("请输入密码:");
        String password = sc.nextLine();
        //向服务器传递状态码
        output(bw,"1");
        //将用户名和密码拼接成指定形式
        StringBuilder sb = new StringBuilder();
        sb.append("username=").append(name).append("&password=").append(password);
        //把登陆数据写出到服务端
        output(bw,sb.toString());
        //获取服务器发回的登陆信息
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String loginCode = br.readLine();
        if(loginCode.equals("1")){
            System.out.println("登陆成功!请开始聊天");
            //创建一个新的线程用于接受消息
            new Thread(new clientThread(socket)).start();
            //开始聊天
            chat2All(bw);
        } else if (loginCode.equals("2")) {
            System.out.println("密码错误,登陆失败!");
        } else if (loginCode.equals("3")) {
            System.out.println("用户名不存在!");
        }


    }
    //聊天操作
    public static void chat2All(BufferedWriter bw) throws IOException {
        while (true){
            System.out.println("请输入聊天内容:");
            Scanner sc = new Scanner(System.in);
            String massage = sc.nextLine();
            output(bw,massage);
        }

    }
    //注册操作
    public static boolean register(Socket socket) throws IOException {
        //输入要注册的用户名和密码
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        Scanner sc = new Scanner(System.in);
        System.out.println("您正在进行注册操作");
        System.out.println("请输入用户名:");
        String name = sc.nextLine();
        System.out.println("请输入密码:");
        String password = sc.nextLine();
        //向服务器传递状态码
        output(bw,"2");
        //对用户名密码进行判断是否判断符合规则
        boolean nameBool = name.matches("[a-zA-Z]{6,18}");
        boolean passwordBool = password.matches("[a-zA-Z]\\d{2,7}");
        if(nameBool){
            if(passwordBool){
                //符合规范则将用户名密码传递给服务器
                StringBuilder sb = new StringBuilder();
                sb.append("username=").append(name).append("&password=").append(password);
                output(bw,sb.toString());
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String registerCode = br.readLine();
                if (registerCode.equals("4")) {
                    System.out.println("用户名存在,请重新操作!");
                } else if (registerCode.equals("5")) {
                    System.out.println("注册成功");
                    return true;
                }
            }else {
                System.out.println("密码不符合规范,密码长度3~8位。第一位必须是小写或者大小的字母,后面必须是纯数字。");
            }
        }else{
            System.out.println("用户名不符合规范,长度:6~18位,纯字母,不能有数字或其他符号。");
        }

        return false;
    }
    public static void output(BufferedWriter bw , String massage) throws IOException {
        bw.write(massage);
        bw.newLine();
        bw.flush();
    }
}
class clientThread implements Runnable{
    Socket socket;
    public  clientThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            while(true){
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String massage = br.readLine();
                System.out.println(massage);
            }



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

    }
}

服务器端:

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);

        Properties properties = new Properties();
        properties.load(new FileReader("src\\userdata.txt"));
        while(true){
            Socket socket = ss.accept();
            System.out.println("已连接客户端!");
            Thread thread = new Thread(new thread(socket,properties));
            thread.start();
        }

    }
}
class thread implements Runnable{
    Socket socket;
    Properties properties;
    public thread(Socket socket,Properties properties){
        this.socket = socket;
        this.properties = properties;
    }
    @Override
    public void run() {
        try {
            //读取客户端传递来的数据
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while(true){
                String choose = br.readLine();
                //对客户端传递的状态码进行判断
                switch (choose) {
                    case "1" -> login();
                    case "2" -> register();
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    //注册
    private void register() throws IOException {
        System.out.println("用户进行注册操作");
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String userData = br.readLine();

        //对传递过来的用户数据进行处理
        String[] user = userData.split("&");
        String name = user[0].split("=")[1];
        String password = user[1].split("=")[1];

        //对用户名进行判断是否唯一
        if (properties.containsKey(name)) {
            //用户名存在
            output("4");
        }else {
            //用户名不存在则将用户数据写入userdata.txt中
            properties.put(name,password);
            properties.store(new FileWriter("src\\userdata.txt"),"test");
            output("5");
        }

    }
    //登陆
    private void login() throws IOException {
        System.out.println("用户正在进行登陆操作");
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String userData = br.readLine();
        //处理接受的数据
        String[] split = userData.split("&");
        String name = split[0].split("=")[1];
        String password = split[1].split("=")[1];
        //读取本地文件验证用户名和密码是否正确
        if (properties.containsKey(name)) {
            //用户名存在
            //判断密码是否正确
            if (properties.get(name).equals(password)) {
                //1.密码正确,登陆成功
                output("1");
                //登陆成功后将本线程的socket对象保存在list集合中
                server.list.add(socket);
                //进入聊天操作
                chat2All(br,name);
            }else{
                //2.密码错误,登陆失败
                output("2");
            }

        }else{
            //用户名不存在
            //输出提示或状态码
            output("3");
        }
    }
    private void chat2All(BufferedReader br,String name) throws IOException {
        while (true){
            //获取消息
            String massage = br.readLine();
            System.out.println(name+":"+massage);
            //将消息转发
            for (Socket s : server.list) {
                output(s,name+":"+massage);
            }
        }
    }
    //向客户端输出提示码
    private void output(String string) throws IOException {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write(string);
        bw.newLine();
        bw.flush();
    }
    private void output(Socket socket,String string) throws IOException {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write(string);
        bw.newLine();
        bw.flush();
    }
}

基于黑马程序员相关课程编写,课程地址:黑马程序员Java零基础视频教程_下部(Java入门,含斯坦福大学练习题+力扣算法题和大厂java面试题)_哔哩哔哩_bilibili

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZEALERHE

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

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

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

打赏作者

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

抵扣说明:

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

余额充值