使用基于TCP协议的Socket编程模拟多用户网络登陆

一、需求

  • 完成多用户网络登陆功能

  • 用户输入用户名密码,服务器给出登陆成功或失败的提示

二、分析:

  • 使用基于TCP协议的Socket网络编程实现
  • TCP协议基于请求-响应模式
  • 在网络通信中,第一次主动发起通讯的程序被称作客户端(Client)程序
  • 第一次通知等待连接的程序被称为服务器端(Server)程序
  • 利用IO流实现数据的传输
    使用基于TCP协议的Socket编程模拟多用户网络登陆_第1张图片

三、服务器端

思路
1、指定端口,使用ServerSocket创建服务器;
2、阻塞式等待连接(accept()方法);
3、通过I/O流获取数据并进行分析;
4、释放资源;

代码:

  将具体的操作封装在一个内部类里,当有一个客户端连接服务器后都可以创建一个子线程来实现其功能;

public class TCPServer {

	public static void main(String[] args) throws IOException {
        // 1、指定端口,使用ServerSocket创建服务器
        ServerSocket serverSocket = new ServerSocket(8888);
        // 2、阻塞式等待连接 accept
        boolean flag = true;
        while (flag) {
            Socket socket = serverSocket.accept();
            System.out.println("有一个客户端连接了服务器");
            new Thread(new Channel(socket)).start();

        }
        serverSocket.close();
    }

    static class Channel implements Runnable{
        private Socket socket;
        DataInputStream dis;  //输入流
        DataOutputStream dos; //输出流
        public Channel(Socket socket) {
            this.socket = socket;
            try {
                dis = new DataInputStream(this.socket.getInputStream());
                dos = new DataOutputStream(this.socket.getOutputStream()); 
            } catch (IOException e) {
                e.printStackTrace();
                release();
            }

        }
        @Override
        public void run() {

            System.out.println("客户端连接成功");
            // 3、操作:输入输出流
            String uName = "";
            String uPwd = "";
            //分析数据
            String[] dataArray = receive().split("&");
            for (String info : dataArray) {
                String[] userInfo = info.split("=");

                if (userInfo[0].equals("userName")) {
                    System.out.println("你的用户名为:" + userInfo[1]);
                    uName = userInfo[1];
                } else {
                    System.out.println("你的密码为:" + userInfo[1]);
                    uPwd = userInfo[1];
                }
            }
            //输出
            if (uName.equals("daria") && uPwd.equals("123")) {
                send("登录成功");
            } else {
                send("用户名或密码错误,请重新输入");
            }
            release();


        }
        //接收数据
        private String receive() {
            String datas = "";
            try {
                datas = dis.readUTF();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return datas;
        }
        private void send(String msg) {
            try {
                dos.writeUTF(msg);
                dos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        //释放资源
        private void release() {
            try {
                if (null != dos) {
                    dos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (null != dis) {
                    dis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (null != socket) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

四、客户端

思路:

1、建立连接 使用Socket创建客户端+服务器地址和端口;
2、通过I/O流向服务端发送数据或接收响应数据;
3、结束请求,释放资源;

代码:

将数据的发送和接收各自封装成一个内部类里,方便维护;

public class TCPClient {
    static class Send { //发送消息
        private DataOutputStream dos;
        private Socket socket;
        private Scanner scanner;
        private String msg;
        public Send(Socket socket) {
            this.scanner = new Scanner(System.in);
            this.msg = this.init();
            this.socket = socket;
            try {
                dos = new DataOutputStream(this.socket.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        private void send() {

            try {
                dos.writeUTF(this.msg);
                dos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        private String  init() {
            System.out.println("请输入用户名");
            String userName = this.scanner.nextLine();
            System.out.println("请输入密码");
            String userPwd = this.scanner.nextLine();
            return "userName=" + userName + "&" + "userPwd=" + userPwd;
        }

    }

    static class Receive { //接收消息
        private DataInputStream dis;
        Socket socket;
        public Receive(Socket socket) {
            this.socket = socket;
            try {
                dis = new DataInputStream(this.socket.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public void receive() {
            String result = null;
            try {
                result = dis.readUTF();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(result);
        }
    }
    public static void main(String[] args) throws IOException {
        
        // 1、建立连接 使用Socket创建客户端+服务器地址和端口
        Socket socket = new Socket("127.0.0.1",8888);
        // 2、操作:输入输出流
        new Send(socket).send();
        new Receive(socket).receive();
        // 3、释放资源
        socket.close();
    }
}

五、测试

  因为没有连接数据库无法判定输入的用户名跟密码是否正确,所以在这里就指定了用户名daria和密码123来对输入的信息进行校验;
使用基于TCP协议的Socket编程模拟多用户网络登陆_第2张图片
使用基于TCP协议的Socket编程模拟多用户网络登陆_第3张图片
使用基于TCP协议的Socket编程模拟多用户网络登陆_第4张图片

你可能感兴趣的:(网络编程)