• Java 网络编程 -- 基于TCP 模拟多用户登录


    Java TCP的基本操作参考前一篇:Java 网络编程 – 基于TCP实现文件上传

    实现多用户操作之前先实现以下单用户操作,假设目前有一个用户:
    账号:zs
    密码:123

    服务端:

    public class LoginServer {
    	public static void main(String[] args) throws IOException {
    		System.out.println("=========server========");
    		// 1、使用serverSocket 创建服务端
    		ServerSocket server = new ServerSocket(8888);
    		// 2、阻塞式连接
    		Socket socket = server .accept();
    		// 3、操作
    		DataInputStream dis = new DataInputStream(socket.getInputStream());
    		String datas = dis.readUTF();
    		// 解析用户信息
    		String[] dataArray = datas.split("&");
    		String uname = null;
    		String pwd = null;
    		for (String info : dataArray) {
    			String[] userInfo = info.split("=");
    			if("uname".equals(userInfo[0])) {
    				uname = userInfo[1];
    				System.out.println("用户名:" + uname);
    			}else if("pwd".equals(userInfo[0])) {
    				pwd = userInfo[1];
    				System.out.println("密码:" + pwd);
    			}
    		}
    		// 输出 模拟和数据库比较信息
    		DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
    		if(uname.equals("zs") && pwd.equals("123")) {
    			dos.writeUTF("登录成功,欢迎回来");
    		}else {
    			dos.writeUTF("用户名或密码错误");
    		}
    		// 4、释放资源
    		dos.close();
    		dis.close();
    		socket.close();
    		server.close();
    	}
    }
    

    客户端:

    public class LoginClient {
    	public static void main(String[] args) throws IOException, IOException {
    		System.out.println("=========client========");
    		// 1、使用Socket 创建客户端
    		Socket client = new Socket("localhost", 8888);
    		// 2、操作
    		// 输入
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		System.out.print("请输入用户名:");
    		String uname = br.readLine();
    		System.out.print("请输入用密码:");
    		String pwd = br.readLine();
    		DataOutputStream dos = new DataOutputStream(client.getOutputStream());
    		dos.writeUTF("uname=" + uname +"&pwd=" + pwd);
    		dos.flush();
    		// 接收服务端响应
    		DataInputStream dis = new DataInputStream(client.getInputStream());
    		String response = dis.readUTF();
    		System.out.println(response);
    		// 3、释放资源
    		dis.close();
    		dos.close();
    		br.close();
    		client.close();
    	}
    }
    

    运行测试:
    在这里插入图片描述

    现在实现了一个用户登录操作,接下来模拟多用户登录。
    对于服务端来说一个连接就是一个socket,要满足多用户登录的需求,如果直接在现有代码上加上while循环,需要一个用户操作完,下一个用户接着操作,这样很不合理,明显的我们要加入多线程,并且现在所有代码都写在main 方法里面,不好维护。

    如果使用lambda表达式,代码比较多,看起来比较累。

    我们还是用静态内部类封装一下每一个类

    封装服务端:

    public class LoginMultiServer {
    	public static void main(String[] args) throws IOException {
    		System.out.println("=========server========");
    		// 1、使用serverSocket 创建服务端
    		ServerSocket server = new ServerSocket(8888);
    		boolean isRuning = true;
    		while (isRuning) {
    			// 2、阻塞式连接
    			Socket socket = server.accept();
    			System.out.println("一个客户端建立了连接");
    			// 3、操作
    			new Thread(new Channel(socket)).start();
    		}
    		server.close();
    	}
    	
    	// 一个Channel 代表一个客户端
    	static class Channel implements Runnable{
    		private Socket socket;
    		private DataInputStream dis;
    		private DataOutputStream dos;
    		
    		public Channel(Socket socket) {
    			this.socket = socket;
    			try {
    				// 输入
    				dis = new DataInputStream(socket.getInputStream());
    				// 输出
    				dos = new DataOutputStream(socket.getOutputStream());
    			} catch (IOException e) {
    				e.printStackTrace();
    				release(); // 一个出错就不用玩了
    			}
    			
    		}
    		
    		// 接收数据
    		public String receive() {
    			String datas = "";
    			try {
    				datas = dis.readUTF();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    			return datas;
    		}
    		
    		// 发送数据
    		public void send(String msg) {
    			try {
    				dos.writeUTF(msg);
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		// 释放资源
    		public 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 != dos)
    				socket.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		@Override
    		public void run() {
    			
    			// 3、操作
    			String datas = receive();
    			// 解析用户信息
    			String[] dataArray = datas.split("&");
    			String uname = null;
    			String pwd = null;
    			for (String info : dataArray) {
    				String[] userInfo = info.split("=");
    				if ("uname".equals(userInfo[0])) {
    					uname = userInfo[1];
    					System.out.println("用户名:" + uname);
    				} else if ("pwd".equals(userInfo[0])) {
    					pwd = userInfo[1];
    					System.out.println("密码:" + pwd);
    				}
    			}
    			// 输出 模拟和数据库比较信息
    			if (uname.equals("zs") && pwd.equals("123")) {
    				send("登录成功,欢迎回来");
    			} else {
    				send("用户名或密码错误");
    			}
    			// 4、释放资源
    			release();
    		}
    		
    	}
    }
    

    封装客户端:

    public class LoginMultiClient {
    	public static void main(String[] args) throws IOException, IOException {
    		System.out.println("=========client========");
    		// 1、使用Socket 创建客户端
    		Socket client = new Socket("localhost", 8888);
    		// 2、操作
    		// 输入
    		new Send(client).send();
    		// 接收服务端响应
    		new Receive(client).receice();
    		// 3、释放资源
    		client.close();
    	}
    	
    	// 发送
    	static class Send{
    		private Socket client;
    		private BufferedReader br;
    		private DataOutputStream dos;
    		private String msg;
    		public Send(Socket client) {
    			try {
    				this.client = client;
    				br = new BufferedReader(new InputStreamReader(System.in));
    				this.msg = init();
    				dos = new DataOutputStream(client.getOutputStream());
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		private String init() {
    			try {
    				System.out.print("请输入用户名:");
    				String uname = br.readLine();
    				System.out.print("请输入用密码:");
    				String pwd = br.readLine();
    				return "uname=" + uname +"&pwd=" + pwd;
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    			return "";
    		}
    		
    		public void send() {
    			try {
    				dos.writeUTF(this.msg);
    				dos.flush();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	// 接收
    	static class Receive{
    		private Socket client;
    		private DataInputStream dis;
    		public Receive(Socket client) {
    			this.client = client;
    			try {
    				dis = new DataInputStream(client.getInputStream());
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    		public void receice() {
    			String response;
    			try {
    				response = dis.readUTF();
    				System.out.println(response);
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    封装之后,main 方法里可以比较简洁的书写逻辑代码了。

    运行测试:
    在这里插入图片描述

    重视基础,才能走的更远。
  • 相关阅读:
    Hubble.net 持久化方面3个重大改进
    并行排序算法
    var_dump打印变量的相关信息
    out of socket memory相关tcp参数
    lsof命令使用示例
    tcp_max_orphans
    print_r打印关于变量的易于理解的信息
    linux动态加载库
    pfiles命令
    var_export输出或返回一个变量的字符串表示
  • 原文地址:https://www.cnblogs.com/xzlf/p/12681517.html
Copyright © 2020-2023  润新知