多人聊天室项目 BIO模型实现

BIO模型聊天室项目大体设计

BIO编程模型

在这里插入图片描述

  • Acceptor是服务器端负责监听具体端口的Socket
  • 每有一个客户端Client连接到服务器端,Acceptor就创建一个新的线程Handler来处理客户端发送的消息
  • 每一个客户端都有一个唯一的Handler来对应处理其事务
  • 为保证线程安全,简单地使用了synchronized来保证

时序图

在这里插入图片描述

服务器端Server代码实现

ChatServer实现

package server;import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;public class ChatServer {//定义Socket需要监听的端口private int DEFAULT_PORT = 8888;private final String QUIT = "quit";private ServerSocket serverSocket;private Map<Integer, Writer> connectedClients;public ChatServer() {connectedClients = new HashMap<>();}public synchronized void addClient(Socket socket) throws IOException {if (socket != null) {int port = socket.getPort();BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));connectedClients.put(port, writer);System.out.println("客户端[" + port + "]已连接到服务器");}}public synchronized void removeClient(Socket socket) throws IOException {if (socket != null) {int port = socket.getPort();if (connectedClients.containsKey(port)) {connectedClients.get(port).close();}connectedClients.remove(port);System.out.println("客户端[" + port + "]已断开连接");}}public synchronized void forwardMessage(Socket socket, String fwdMsg) throws IOException {for (Integer id : connectedClients.keySet()) {if (!id.equals(socket.getPort())) {Writer writer = connectedClients.get(id);writer.write(fwdMsg);writer.flush();}}}public boolean readyToQuit(String msg) {return QUIT.equals(msg);}public synchronized void close() {if (serverSocket != null) {try {serverSocket.close();System.out.println("关闭serverSocket");} catch (IOException e) {e.printStackTrace();}}}public void start() {try {// 绑定监听端口serverSocket = new ServerSocket(DEFAULT_PORT);System.out.println("启动服务器,监听端口:" + DEFAULT_PORT + "...");while (true) {// 等待客户端连接Socket socket = serverSocket.accept();// 创建ChatHandler线程new Thread(new ChatHandler(this, socket)).start();}} catch (IOException e) {e.printStackTrace();} finally {close();}}public static void main(String[] args) {ChatServer server = new ChatServer();server.start();}}

ChatHanlder实现

package server;import java.io.*;
import java.net.Socket;public class ChatHandler implements Runnable {private ChatServer server;private Socket socket;public ChatHandler(ChatServer server, Socket socket) {this.server = server;this.socket = socket;}@Overridepublic void run() {try {// 存储新上线用户server.addClient(socket);// 读取用户发送的消息BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = null;while ((msg = reader.readLine()) != null) {String fwdMsg = "客户端[" + socket.getPort() + "]: " + msg + "\n";System.out.print(fwdMsg);// 将消息转发给聊天室里在线的其他用户server.forwardMessage(socket, fwdMsg);// 检查用户是否准备退出if (server.readyToQuit(msg)) {break;}}} catch (IOException e) {e.printStackTrace();} finally {try {server.removeClient(socket);} catch (IOException e) {e.printStackTrace();}}}
}

客户端Client代码实现

ChatClient实现

package client;import java.io.*;
import java.net.Socket;public class ChatClient {//定义目标服务器的主机名和端口private final String DEFAULT_SERVER_HOST = "127.0.0.1";private final int DEFAULT_SERVER_PORT = 8888;private final String QUIT = "quit";//定义Socket和输入流,输出流private Socket socket;private BufferedReader reader;private BufferedWriter writer;// 发送消息给服务器public void send(String msg) throws IOException {if (!socket.isOutputShutdown()) {writer.write(msg + "\n");writer.flush();}}// 从服务器接收消息public String receive() throws IOException {String msg = null;if (!socket.isInputShutdown()) {msg = reader.readLine();}return msg;}// 检查用户是否准备退出public boolean readyToQuit(String msg) {return QUIT.equals(msg);}public void close() {if (writer != null) {try {System.out.println("关闭socket");writer.close();} catch (IOException e) {e.printStackTrace();}}}public void start() {try {// 创建socketsocket = new Socket(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT);// 创建IO流reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));// 处理用户的输入new Thread(new UserInputHandler(this)).start();// 读取服务器转发的消息String msg = null;while ((msg = receive()) != null) {System.out.println(msg);}} catch (IOException e) {e.printStackTrace();} finally {close();}}public static void main(String[] args) {ChatClient chatClient = new ChatClient();chatClient.start();}
}

UserInputHanlder实现

package client;import client.ChatClient;
import java.io.*;public class UserInputHandler implements Runnable {private ChatClient chatClient;public UserInputHandler(ChatClient chatClient) {this.chatClient = chatClient;}@Overridepublic void run() {try {// 等待用户输入消息BufferedReader consoleReader =new BufferedReader(new InputStreamReader(System.in));while (true) {String input = consoleReader.readLine();// 向服务器发送消息chatClient.send(input);// 检查用户是否准备退出if (chatClient.readyToQuit(input)) {break;}}} catch (IOException e) {e.printStackTrace();}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/483237.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云平台 - Stable Diffusion WebUI 下载模型

1&#xff09;进入控制台&#xff0c;点击算力连接 》 JupyterLab 2&#xff09;进入模型目录&#xff08;双击&#xff09; 3&#xff09;上传模型 例如&#xff1a;我要上传大模型

夜神模拟器+Charles+postern+Mgisk+TrustMeAlready实现抓包

[实测有用]夜神模拟器CharlesposternMgiskTrustMeAlready实现抓包 PS:此贴仅做为技术交流,禁止非法用途。 1.初始化条件 A.安装MUMU模拟器安卓12版本 B.按图示选择&#xff0c;设置好代理端口8889 C.查看本机IP地址 D.导出证书&#xff0c;安装配置&#xff0c;暂时保存…

【closerAI ComfyUI】物体转移术之图案转移,Flux三重控制万物一致性生图,实现LOGO和图案的精准迁移

更多AI前沿科技资讯,请关注我们:closerAI-一个深入探索前沿人工智能与AIGC领域的资讯平台 closerAIGCcloserAI,一个深入探索前沿人工智能与AIGC领域的资讯平台,我们旨在让AIGC渗入我们的工作与生活中,让我们一起探索AIGC的无限可能性! 【closerAI ComfyUI】物体转移术之图…

新质驱动·科东软件受邀出席2024智能网联+低空经济暨第二届湾区汽车T9+N闭门会议

为推进广东省加快发展新质生产力&#xff0c;贯彻落实“百县千镇万村高质量发展工程”&#xff0c;推动韶关市新丰县智能网联新能源汽车、低空经济与数字技术的创新与发展&#xff0c;充分发挥湾区汽车产业链头部企业的带动作用。韶关市指导、珠三角湾区智能网联新能源汽车产业…

vue+mars3d给影像底图叠加炫酷效果

话不多说&#xff0c;直接上效果图&#xff1a; 在这里墙体其实是有一个不太明显的流动效果 实现方式&#xff1a;这里我使用了PolylineEntityWallPrimitive&#xff0c;开始我用的是polygonEntity但是发现实现效果并不好&#xff0c;所有直接改用了线 map.vue文件&#xff1…

【模电】常见电路参数计算

1.恒流源输出电阻 2.射极电压跟随器输出电阻 3.差分放大电路 3.1差模特性 3.1.1差模输入电阻Rid 3.1.2差模输出电阻Ro 3.1.3差模电压增益Avd 3.2共模特性 3.2.1共模输入电阻Ric 3.2.2共模电压增益Avc 4.组合放大电路 4.1单级放大器 4.1.1微变等效电路 4.1.1.1共射级 4.1.…

Linux-虚拟环境

文章目录 一. 虚拟机二. 虚拟化软件三. VMware WorkStation四. 安装CentOS操作系统五. 在VMware中导入CentOS虚拟机六. 远程连接Linux系统1. Finalshell安装2. 虚拟机网络配置3. 连接到Linux系统 七. 虚拟机快照 一. 虚拟机 借助虚拟化技术&#xff0c;我们可以在系统中&#…

Kafka如何保证消息可靠?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka如何保证消息可靠&#xff1f;】面试题。希望对大家有帮助&#xff1b; Kafka如何保证消息可靠&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Kafka通过多种机制来确保消息的可靠性&#xff0c;主要包…

ONVIF协议网络摄像机客户端使用gsoap获取RTSP流地址GStreamer拉流播放

什么是ONVIF协议 ONVIF&#xff08;开放式网络视频接口论坛&#xff09;是一个全球性的开放式行业论坛&#xff0c;旨在促进开发和使用基于物理IP的安全产品接口的全球开放标准。 ONVIF规范的目标是建立一个网络视频框架协议&#xff0c;使不同厂商生产的网络视频产品完全互通。…

javaweb_Day05

1.请求响应 1.1 概述 1.2 请求 1.2.1 请求参数 1.2.2 响应 2.分层解耦 2.1 三层架构 &#xff08;1&#xff09;代码分层 2.2 分层解耦 2.3 IOC&DI入门 &#xff08;1&#xff09;控制反转IOC &#xff08;2&#xff09;依赖注入DI &#xff08;3&#xff09;汇总 …

Stable Diffusion 3详解

&#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&…

[VUE]框架网页开发02-如何打包Vue.js框架网页并在服务器中通过Tomcat启动

在现代Web开发中&#xff0c;Vue.js已经成为前端开发的热门选择之一。然而&#xff0c;将Vue.js项目打包并部署到生产环境可能会让一些开发者感到困惑。本文将详细介绍如何将Vue.js项目打包&#xff0c;并通过Tomcat服务器启动运行。 1. 准备工作 确保你的项目能够正常运行,项…

网络分层模型( OSI、TCP/IP、五层协议)

1、网络分层模型 计算机网络是一个极其复杂的系统。想象一下最简单的情况&#xff1a;两台连接在网络上的计算机需要相互传输文件。不仅需要确保存在一条传输数据的通路&#xff0c;还需要完成以下几项工作&#xff1a; 发起通信的计算机必须激活数据通路&#xff0c;这包括发…

采药 刷题笔记 (动态规划)0/1背包

P1048 [NOIP2005 普及组] 采药 - 洛谷 | 计算机科学教育新生态 动态规划 0/1背包 的本质在于继承 一行一行更新 上一行是考虑前i个物品的最优情况 当前行是考虑第i1个物品的情况 当前行的最优解 来自上一行和前i个物品的最优解进行比较 如果当前装了当前物品&#xff…

汽车操作系统详解

目录 1. 车控汽车操作系统 2. 车载汽车操作系统 3. OEM定制操作系统 刚开始工作的时候&#xff0c;接触的是汽车控制相关的开发工作&#xff0c;天真地以为汽车操作系统就是指实时操作系统&#xff0c;例如FreeRTOS、OSEK OS、AUTOSAR OS等等&#xff1b;然而&#xff0c;随…

Shire 1.1 发布:更强大的交互支持,升级 AI 智能体与 IDE 的整合体验

在经过多个项目上的试用后&#xff0c;我们进入了持续的修修补补&#xff0c;以及功能的增强阶段。终于&#xff0c;我们发布了 Shire 1.1 版本&#xff0c;这个版本带来了更强大的交互支持&#xff0c; 多功能升级 AI 与 IDE 的整合体验。 交互&#xff1a;丰富与大量 IDE 插件…

Springboot(四十九)SpringBoot3整合jetcache缓存

上文中我们学习了springboot中缓存的基本使用。缓存分为本地caffeine缓存和远程redis缓存。现在有一个小小的问题,我想使用本地caffeine缓存和远程redis缓存组成二级缓存。还想保证他们的一致性,这个事情该怎么办呢? Jetcache框架为我们解决了这个问题。 ‌JetCache‌是一个…

学习笔记052——Spring Boot 自定义 Starter

文章目录 Spring Boot 自定义 Starter1、自定义一个要装载的项目2、创建属性读取类 ServiceProperties3、创建 Service4、创建自动配置类 AutoConfigration5、创建 spring 工程文件6、将项目打成 jar 包7、jar 打包到本地仓库8、配置application.yml Spring Boot 自定义 Starte…

专业清洁艺术,还原生活本色——友嘉高效除菌洗碗机

生活中&#xff0c;每个人都渴望拥有一份洁净的生活环境。而家&#xff0c;作为我们最温馨的港湾&#xff0c;对洁净的追求更是无时无刻不在进行。每当饭后的欢声笑语过后&#xff0c;面对一堆沾满油渍、藏匿着细菌的餐具&#xff0c;我们不禁感到一丝烦忧。然而&#xff0c;有…

C++类与对象(二)

一、默认成员函数 class A{}; 像上面一样&#xff0c;一个什么都没有的类叫做空类&#xff0c;但是这个什么都没有并不是真正的什么都没有&#xff0c;只是我们看不见&#xff0c;空类里面其实是有6个默认成员函数的&#xff0c;当我们在类里面什么都不写的时候&#xff0c;编译…