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

目录:

目录

目录:

一、使用到的知识点:循环,判断,集合,IO,多线程,网络编程等

二、总结缺点:

三、知识点:

在 Properties 对象中,键值对是根据以下规则分配的:

四、文件构造

1.客户端:Client,java

 2.聊天记录:ClientMyRunnable.java

3.服务端:Server.java

4.多线程:MyRunnable

5.配置文件:userinfo.txt


一、使用到的知识点:循环,判断,集合,IO,多线程,网络编程等

二、总结缺点:

1.应该使用Properties prop = new Properties(); 双列集合,
获取配置文件中的名称和密码(否则需要的变量太多,太乱)
2.太多异常需要捕获,应该抽出一个方法,尽量进行抛出,需要捕获的异常尽量放一块
3.一个类中 不要放太多输入输出流,可以的话就写一个,然后,需要用就作为参数传递。
4.字符串的拼接尽量用 StringBuilder进行拼接,方便而且节省运行时间
5.需要使用多线程的方法,优先放进多线程的run方法中。

三、知识点:

在 Properties 对象中,键值对是根据以下规则分配的:

1.键:每一行的第一个部分,直到遇到第一个等号(=)或冒号(:)为止。键通常是字符串类型。
2.值:等号或冒号之后的部分,直到行尾。值可以是字符串、数字、布尔值等。
3.注释:以 # 开头的行被视为注释,不会被加载为键值对。

四、文件构造

1.客户端:Client,java
package com.itheima.client;

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", 10001);
        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 register(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();

        //拼接
        //username=zhangsan&password=123
        StringBuilder sb = new StringBuilder();
        sb.append("username=").append(username).append("&password=").append(password);

        //第一次写的是执行注册
        bw.write("register");
        bw.newLine();//换行
        bw.flush();

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

        //接收数据
        //获取输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String message = br.readLine();
        System.out.println(message);
        //0:注册成功  1:密码格式不正确 2:用户名格式不正确   3 用户名已存在
        if ("0".equals(message)) {
            System.out.println("注册成功,开始聊天");
            //开一条单独的线程,专门用来接收服务端发送过来的聊天记录
            new Thread(new ClientMyRunnable(socket)).start();
            //开始聊天
            talk2All(bw);
        } else if ("1".equals(message)) {
            System.out.println("密码格式错误");
        } else if ("2".equals(message)) {
            System.out.println("用户名格式错误");
        } else if ("3".equals(message)) {
            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 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);

        //第一次写的是执行登录操作
        bw.write("login");
        bw.newLine();
        bw.flush();

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

        //接收数据
        //获取输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String message = br.readLine();
        System.out.println(message);
        //1:登录成功  2 密码有误   3 用户名不存在
        if ("1".equals(message)) {
            System.out.println("登录成功,开始聊天");
            //开一条单独的线程,专门用来接收服务端发送过来的聊天记录
            new Thread(new ClientMyRunnable(socket)).start();
            //开始聊天
            talk2All(bw);
        } else if ("2".equals(message)) {
            System.out.println("密码输入错误");
        } else if ("3".equals(message)) {
            System.out.println("用户名不存在");
        }

    }

    //往服务器写出消息
    private static void talk2All(BufferedWriter bw) throws IOException {
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入您要说的话");
            String str = sc.nextLine();
            //把聊天内容写给服务器
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
    }
}

 2.聊天记录:ClientMyRunnable.java
package com.itheima.client;

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

class ClientMyRunnable implements Runnable{
    Socket socket;
    public ClientMyRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {

        //循环,重复的接受
        while (true) {
            try {
                //接收服务器发送过来的聊天记录
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String msg = br.readLine();
                System.out.println(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

3.服务端:Server.java
package com.itheima.server;

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

        //1.把本地文件中正确的用户名和密码获取到
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream("D:\\java\\Project\\base2-code\\sockethomework\\servicedir\\userinfo.txt");
        prop.load(fis);
        System.out.println(prop.get("lisi"));
        fis.close();

        //2.只要来了一个客户端,就开一条线程处理
        while (true) {
            Socket socket = ss.accept();
            System.out.println("有客户端来链接");
            new Thread(new MyRunnable(socket, prop)).start();
        }
    }
}


4.多线程:MyRunnable
package com.itheima.server;

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

class MyRunnable implements Runnable {
    Socket socket;
    Properties prop;

    public MyRunnable(Socket socket, Properties prop) {
        this.prop = prop;
        this.socket = socket;
    }

    @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" -> register(br);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取用户注册时,传递过来的信息。
    //并进行判断
    public void register(BufferedReader br) throws IOException {
        System.out.println("用户选择了注册操作:");
        String userinfo = br.readLine();
        //username=zhangsan&password=123
        String[] userInfoArr = userinfo.split("&");
        String usernameInput = userInfoArr[0].split("=")[1];
        String passwordInput = userInfoArr[1].split("=")[1];
        System.out.println("用户输入的用户名为:" + usernameInput);
        System.out.println("用户输入的密码为:" + passwordInput);
        if(!prop.containsKey(usernameInput)){
            //如果用户名不存在,继续判断
            //判断用户名格式
            boolean flag1 = usernameInput.matches("[a-zA-Z]{6,18}");
            if(flag1){
                //用户名格式正确,继续判断
                //判断密码格式
                boolean flag2 = passwordInput.matches("[a-zA-Z]\\d{2,7}");
                if(flag2){
                    //将用户写道配置文件中
                    //zhangsan=123
                    StringBuilder sb = new StringBuilder();
                    sb.append(usernameInput).append(passwordInput);
                    prop.put(usernameInput,passwordInput);
                    pezhi(prop);
                    //密码格式正确,提示用户开始聊天
                    writeMessage2Client("0");
                    //注册成功的时候,就需要把客户端的连接对象Socket保存起来
                    Server.list.add(socket);
                    //写一个while(){}表示正在聊天
                    //接收客户端发送过来的消息,并打印在控制台
                    talk2All(br, usernameInput);
                }else{
                    //密码格式不正确,直接回写
                    writeMessage2Client("1");
                }
            }else{
                //用户名格式不正确,直接回写
                writeMessage2Client("2");
            }
        }else{
            //如果用户名存在,直接回写
            writeMessage2Client("3");
        }


    }

    //获取用户登录时,传递过来的信息。
    //并进行判断
    public void login(BufferedReader br) throws IOException {
        System.out.println("用户选择了登录操作");
        String userinfo = br.readLine();
        //username=zhangsan&password=123
        String[] userInfoArr = userinfo.split("&");
        String usernameInput = userInfoArr[0].split("=")[1];
        String passwordInput = userInfoArr[1].split("=")[1];
        System.out.println("用户输入的用户名为:" + usernameInput);
        System.out.println("用户输入的密码为:" + passwordInput);

        if (prop.containsKey(usernameInput)) {
            //如果用户名存在,继续判断密码
            String rightPassword = prop.get(usernameInput) + "";
            if (rightPassword.equals(passwordInput)) {
                //提示用户登录成功,可以开始聊天
                writeMessage2Client("1");
                //登录成功的时候,就需要把客户端的连接对象Socket保存起来
                Server.list.add(socket);
                //写一个while(){}表示正在聊天
                //接收客户端发送过来的消息,并打印在控制台
                talk2All(br, usernameInput);
            } else {
                //密码输入有误
                writeMessage2Client("2");
            }
        } else {
            //如果用户名不存在,直接回写
            writeMessage2Client("3");
        }
    }

    private void talk2All(BufferedReader br, String username) throws IOException {
        while (true) {
            String message = br.readLine();
            System.out.println(username + "发送过来消息:" + message);

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

    public void writeMessage2Client(String message) throws IOException {
        //获取输出流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write(message);
        bw.newLine();
        bw.flush();
    }

    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 pezhi( Properties prop) throws IOException {
        //获取输出流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\java\\Project\\base2-code\\sockethomework\\servicedir\\userinfo.txt")));
        Set<Object> set = prop.keySet();
        for(Object key: set ){
            String value = (String) prop.get(key);
            bw.write(key + "=" + value);
            bw.newLine();
            bw.flush();
        }


    }

}
5.配置文件:userinfo.txt
lisi=1234
zhaoliu=a123456
zhangsan=123
wangwu=12345
zhaoyun=a12345

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值