即时通信-群聊

即时通信-群聊

群聊是要把客户端的消息发给多个客户端。

TCP通信-端口转发

服务端代码:

public class ServerDemo {
	public static List<Socket> onLineSockets = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        // 创建ServerSocket对象
        ServerSocket ss = new ServerSocket(10000);

		while(true) {
			// 调用accept等待客户端连接
	        Socket accept = ss.accept();
	        onLineSockets.add(socket);
	        System.out.println("有人上线了:" + socket.getRemoteSocketAddress());
	        // 把这个客户端对应的socket通信管道,交给一个独立的线程负责
	        new ServerReaderThread(accept).start();
		}
    }
}

服务端读数据的多线程代码修改

public class ServerReaderThread extends Thread {
	private Socket socket;
	public ServerReaderThread(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		try {
			// 获取输入流对象
	        InputStream is = accept.getInputStream();
	
			// 把原始的字节输入流包装称数据输入流
			DataInputStream dis = new DataInputStream(is);
			while(true) {
				try {
				// 使用数据输入流读取客户端发送过来的消息
				String rs = dis.readUTF();
				System.out.println(rs);
				// 把这个消息分发给全部客户端进行接收
				sendMsgToAll(rs);
				
		        // 获取客户端的IP地址
		        System.out.println(accept.getRemoteSocketAddress());
			} catch(Exception e) {
				System.out.println(socket.getRemoteSocketAddress() + "离线了");
				Server.onLineSockets.remove(socket);
				dis.close();
				socket.close();
				break;
			}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void sendMsgToAll(String msg) throw IOException{
		// 发送给全部在线的socket管道接收
		for (Socket onLineSocket : Server.onLineSockets) {
			OutputStream os = onLineSocket.getOutputStream();
			DataOutputStream dos = new DataOutputStream(os);
			dos.writeUTF(msg);
			dos.flush();
		}
	}
}

客户端代码:基于TCP多收多发#^889e2d修改

public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 创建一个Socket对象
        Socket socket = new Socket("127.0.0.1", 10000);

		// 创建一个独立线程,负责随机从socket中接收服务端发送过来的消息
		new ClientReaderThread(socket).start();

        // 获取一个IO流开始写数据
        OutputStream os = socket.getOutputStream();

		// 把低级的字节输出流包装称数据输出流
		DataOutputStream dos = new DataOutputStream(os);

		Scanner sc = new Scanner(System.in);
		while(true) {
			System.out.println("请说:");
			String msg = sc.nextLine();


			//exit退出程序
			if("exit".equals(msg)) {
				System.out.println("退出成功");
				dos.close();
				socket.close();
				break;
			}
			// 开始写数据
	        dos.writeUTF("Hello, server");
	        dos.flush();
		}

        // 释放资源
        dos.close();
        socket.close();
    }
}

客户端读取数据的线程

public class ClientReaderThread extends Thread{
	private Socket socket;
	public ClientReaderThread(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		try {
			// 获取输入流对象
	        InputStream is = accept.getInputStream();
	
			// 把原始的字节输入流包装称数据输入流
			DataInputStream dis = new DataInputStream(is);
			while(true) {
				try {
				// 使用数据输入流读取客户端发送过来的消息
				String rs = dis.readUTF();
				System.out.println(rs);
				
		        // 获取客户端的IP地址
		        System.out.println(accept.getRemoteSocketAddress());
			} catch(Exception e) {
				System.out.println("自己下线了:" + socket.getRemoteSocketAddress());
				dis.close();
				socket.close();
				break;
			}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}