Java Socket 多人聊天室(私聊+群聊)技术笔记(V4版本)
一、项目整体架构本项目是基于 BIO 阻塞式 Socket 实现的桌面多人聊天室支持用户登录、群聊、一对一私聊功能搭配Swing实现可视化客户端界面。整体分为服务端、客户端、用户实体、UI界面四大核心模块采用 服务端中转消息 的通信模式所有客户端消息统一发送至服务端由服务端分发转发。1.1 核心模块分工Server服务端监听端口、接收客户端连接、处理用户登录、解析消息类型、转发私聊/群聊消息、维护在线用户列表Client客户端建立服务端连接、用户账号登录、封装私聊/群聊消息、发送消息、接收服务端转发的消息ClientUser用户实体封装在线用户信息账号、Socket连接服务端核心存储对象ClientUI可视化界面基于Swing实现聊天窗口、输入框、发送按钮绑定消息收发事件1.2 通信核心原理基于TCP长连接通信客户端与服务端建立永久Socket连接全程流式传输字节数据通过 自定义消息协议 区分私聊、群聊消息服务端统一调度转发实现多客户端通信。二、自定义通信协议核心重点项目无第三方通信框架完全自定义消息格式通过固定字节顺序解析消息类型、发送目标、消息内容是实现私聊/群聊区分的核心。2.1 消息类型定义1私聊消息定向发送指定用户2群聊消息广播给所有在线用户除发送者自身2.2 完整消息协议格式私聊消息格式消息类型(1字节) 好友名称长度(1字节) 好友名称(字节数组) 消息长度(1字节) 消息内容(字节数组)群聊消息格式消息类型(1字节) 消息长度(1字节) 消息内容(字节数组)登录消息格式账号长度(1字节) 账号名称(字节数组)三、用户实体类ClientUser服务端用于存储所有在线用户的核心实体绑定用户账号与Socket连接实现精准消息转发。packageV4;importjava.net.Socket;/** * 在线用户实体类封装单个客户端的连接信息与账号 * 服务端集合通过该对象维护所有在线用户 */publicclassClientUser{Stringaccount;// 客户端登录账号Socketsocket;// 客户端对应的Socket连接对象// 构造方法登录成功后创建用户对象publicClientUser(Socketsocket,Stringaccount){this.accountaccount;this.socketsocket;}}四、客户端核心实现Client客户端核心功能初始化连接、账号登录、封装发送消息、接收服务端返回消息。所有IO操作基于字节流传输严格遵循自定义协议。packageV4;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.Socket;importjava.util.Scanner;/** * 聊天室客户端核心类 * 负责连接服务端、登录、消息发送、消息接收 */publicclassClient{Socketsocketnull;// 客户端Socket连接对象// 初始化连接服务端 执行登录逻辑publicvoidinit(){try{// 连接本地服务端端口与服务端一致54321socketnewSocket(127.0.0.1,54321);login(socket.getOutputStream());}catch(IOExceptione){thrownewRuntimeException(e);}}// 用户登录向服务端发送账号信息publicvoidlogin(OutputStreamos){ScannerscnewScanner(System.in);System.out.println(请输入账号:);Stringaccountsc.nextLine();byte[]accountsaccount.getBytes();try{// 先发送账号长度再发送账号内容服务端按长度读取避免粘包os.write(accounts.length);os.write(accounts);os.flush();// 强制刷新流确保数据立即发送}catch(IOExceptione){thrownewRuntimeException(e);}}/** * 消息发送核心方法区分私聊/群聊封装协议数据 * 规则消息以开头为私聊否则为群聊 */publicvoidsend(Stringmessage){try{OutputStreamossocket.getOutputStream();// 判断消息类型首字符 代表私聊if(message.charAt(0)){// 拆分私聊格式好友名 消息内容intindexmessage.indexOf( );Stringfriendmessage.substring(1,index);// 截取目标好友账号Stringmsgmessage.substring(index1);// 截取消息内容// 按照私聊协议封装数据os.write(1);// 1私聊类型标识intfidlenfriend.getBytes().length;os.write(fidlen);// 好友名称字节长度os.write(friend.getBytes());// 好友名称字节数据intmsglenmsg.getBytes().length;os.write(msglen);// 消息内容字节长度os.write(msg.getBytes());// 消息内容字节数据}else{// 群聊消息封装os.write(2);// 2群聊类型标识byte[]msgsmessage.getBytes();os.write(msgs.length);// 消息长度os.write(msgs);// 消息内容}os.flush();// 强制刷新完成消息发送}catch(IOExceptione){thrownewRuntimeException(e);}}// 读取服务端转发的消息publicStringreadMsg(){try{InputStreaminssocket.getInputStream();// 先读长度再读内容解决TCP粘包问题intlenins.read();byte[]msgsnewbyte[len];ins.read(msgs);returnnewString(msgs);}catch(IOExceptione){thrownewRuntimeException(e);}}staticvoidmain(){}}4.1 客户端核心关键点备注粘包解决核心所有消息传输遵循「先传长度、再传内容」服务端根据长度精准读取字节避免TCP流式传输导致的粘包、半包问题消息区分规则通过消息首字符判定私聊空格分割好友名称与消息内容流刷新机制每次write后必须执行flush()否则数据会滞留缓冲区无法及时发送五、服务端核心实现Server服务端是整个聊天室的中枢负责监听连接、处理登录、解析消息、转发消息、维护在线用户列表通过多线程支持多客户端同时在线。packageV4;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.ArrayList;/** * 聊天室服务端核心类 * 端口监听、客户端连接管理、消息解析、消息转发 */publicclassServer{ServerSocketssnull;// 全局在线用户列表存储所有已登录的客户端连接ArrayListClientUsersocketlist();// 初始化服务端绑定固定端口54321publicvoidinit(){try{ssnewServerSocket(54321);}catch(IOExceptione){thrownewRuntimeException(e);}}// 监听客户端连接阻塞方法等待客户端接入publicSocketlisten(){try{returnss.accept();}catch(IOExceptione){thrownewRuntimeException(e);}}// 统一消息发送工具服务端向客户端转发消息publicvoidsend(Stringmessage,OutputStreamos){try{// 遵循长度内容协议发送消息intlenmessage.getBytes().length;os.write(len);os.write(message.getBytes());os.flush();}catch(IOExceptione){thrownewRuntimeException(e);}}/** * 消息解析方法读取客户端发送的原始字节流 * 根据消息类型1/2分别解析私聊、群聊数据 * 返回带标识的字符串用于后续转发逻辑处理 */publicStringreceive(InputStreamin){try{inttypein.read();// 读取消息类型if(type1){// 解析私聊消息intfidLenin.read();// 好友名称长度byte[]fidnewbyte[fidLen];in.read(fid);StringfidStrnewString(fid);// 目标好友账号intmlenin.read();// 消息长度byte[]msgsnewbyte[mlen];in.read(msgs);StringmsgnewString(msgs);// 消息内容// 自定义分隔符# 拼接数据方便后续拆分处理return1#fidStr#msg;}else{// 解析群聊消息intlenin.read();byte[]msgsnewbyte[len];in.read(msgs);StringmsgnewString(msgs);return2#msg;}}catch(IOExceptione){thrownewRuntimeException(e);}returnnull;}/** * 处理客户端所有消息的核心方法 * 每个客户端连接单独开启一个子线程实现多客户端并发 */publicvoidproClientMsg(Socketsocket){newThread(()-{// 1. 处理用户登录获取登录账号Stringaccountprologin(socket);// 2. 将在线用户存入集合ClientUserclientUsernewClientUser(socket,account);socketlist.add(clientUser);// 3. 循环监听当前客户端的所有消息while(true){try{InputStreaminclientUser.socket.getInputStream();Stringmsgreceive(in);String[]datasmsg.split(#);// 拆分解析后的消息数据Stringtypedatas[0];// 私聊消息转发逻辑if(type.equals(1)){Stringfiddatas[1];// 目标好友账号Stringmsg1datas[2];// 消息内容// 遍历在线用户列表精准匹配目标用户for(ClientUserotCU:socketlist){if(otCU.account.equals(fid)){// 拼接发送者信息转发给目标用户msg1clientUser.account说msg1;send(msg1,otCU.socket.getOutputStream());break;}}}else{// 群聊消息转发逻辑广播给所有在线用户排除自己Stringmsg1datas[1];msg1clientUser.account说:msg1;for(ClientUserotCU:socketlist){Socketsocket1otCU.socket;if(socket1!clientUser.socket){send(msg1,socket1.getOutputStream());}}}}catch(IOExceptione){thrownewRuntimeException(e);}}}).start();}// 处理用户登录读取客户端发送的账号信息publicStringprologin(Socketsocket){try{InputStreaminsocket.getInputStream();intlenin.read();byte[]msgsnewbyte[len];in.read(msgs);StringaccountnewString(msgs);System.out.println(用户名:account 上线了 );returnaccount;}catch(IOExceptione){thrownewRuntimeException(e);}}// 服务端启动入口staticvoidmain(){ServerservernewServer();server.init();// 循环监听客户端连接主线程阻塞单独开启线程newThread(()-{while(true){System.out.println(监听连接中~);Socketsserver.listen();System.out.println(s.getInetAddress():s.getPort()连接成功);server.proClientMsg(s);// 处理该客户端的所有后续逻辑}}).start();}}5.1 服务端核心关键点备注多线程并发每个客户端连接单独创建子线程处理消息避免单线程阻塞支持多用户同时在线消息转发机制所有消息不直接点对点传输必须经过服务端中转实现统一管理私聊精准匹配通过遍历在线用户集合匹配账号名称实现定向消息发送群聊广播过滤转发群聊消息时排除发送者自身避免自己收到自己的消息数据分隔处理使用#作为自定义分隔符拆分消息类型、目标账号、消息内容解析简单高效六、可视化UI界面实现ClientUI基于Swing实现桌面可视化窗口包含聊天记录展示区、消息输入框、发送按钮同时开启子线程实时接收服务端消息避免UI阻塞。packageV4;importjavax.swing.*;importjava.awt.*;/** * 聊天室可视化客户端界面 * 基于Swing实现绑定消息收发事件 */publicclassClientUIextendsJFrame{ClientclientnewClient();// 绑定客户端核心通信对象publicstaticvoidmain(){ClientUIclientUInewClientUI();clientUI.showUI();}// 初始化展示UI窗口publicvoidshowUI(){// 启动客户端连接登录client.init();// 窗口基础配置JFramejfnewJFrame(小小聊天室);jf.setSize(500,550);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setLocationRelativeTo(null);// 窗口居中// 聊天记录展示区域带滚动条JTextAreamsgAreanewJTextArea();JScrollPanescrollPanenewJScrollPane(msgArea);scrollPane.setPreferredSize(newDimension(0,470));// 消息输入框、发送按钮JTextFieldmsgFieldnewJTextField();msgField.setBackground(Color.pink);JButtonsendBtnnewJButton(发送);msgField.setPreferredSize(newDimension(370,0));sendBtn.setPreferredSize(newDimension(100,0));// 组件布局添加jf.add(scrollPane,BorderLayout.NORTH);jf.add(msgField,BorderLayout.WEST);jf.add(sendBtn,BorderLayout.EAST);jf.setVisible(true);// 绑定发送按钮点击事件sendBtn.addActionListener(e-sendMsg(msgArea,msgField));// 开启子线程实时接收服务端消息刷新UI防止主线程阻塞newThread(()-{while(true){Stringmsgclient.readMsg();msgArea.append(msg\n);// 追加消息到聊天界面}}).start();}// 发送消息事件点击按钮触发publicvoidsendMsg(JTextAreamsgArea,JTextFieldmsgField){StringmsgmsgField.getText();// 本地先展示自己发送的消息msgArea.append(我说msg\n);// 调用客户端方法发送消息到服务端client.send(msg);msgField.setText();// 清空输入框}}6.1 UI核心关键点备注子线程接收消息消息接收是阻塞循环操作必须放在子线程否则会卡死Swing主线程UI刷新线程本地消息回显自己发送的消息本地直接展示服务端只转发他人消息提升体验滚动文本域使用JScrollPane包裹文本域实现聊天记录滚动查看七、项目启动流程总结启动 Server服务端监听54321端口等待客户端连接启动 ClientUI客户端输入账号完成登录服务端记录在线用户客户端输入消息无为群聊好友空格内容为私聊客户端封装协议消息发送至服务端服务端解析消息类型转发至对应目标用户客户端子线程接收转发消息刷新UI展示聊天内容

相关新闻

Anthropic 无人机实验:端到端能力“突然变强”,往往只是最后一个子任务补齐了

Anthropic 无人机实验:端到端能力“突然变强”,往往只是最后一个子任务补齐了

你线上的 Agent 是不是也这样: Demo 时飞得挺漂亮,上线后却撞墙、丢目标、偶发才成功同事说“模型升级了,端到端通了”,你却不知道该信峰值还是均值产品想砍人工审核,你又拿不出“什么时候可以少盯一眼”的标准 这不…

2026/7/29 1:24:07阅读更多 →
Azure Stack Hub 网络服务管理工具与常见问题排错(下篇)

Azure Stack Hub 网络服务管理工具与常见问题排错(下篇)

未经同意,请勿转载! 本篇定位:面向 Azure Stack Hub 一线运维 / SOC / 监控 / 故障响应工程师。本文承接上篇《Azure Stack Hub 网络服务:从物理拓扑到租户 SDN 完整图谱》中网络模型部分,重点展示如何在生产中观测、运…

2026/7/29 1:24:04阅读更多 →
树状数组与线段树的区别、联系及应用场景

树状数组与线段树的区别、联系及应用场景

树状数组与线段树的区别 数据结构特性 树状数组(Binary Indexed Tree, BIT)基于二进制拆分思想,结构为隐式树形,仅支持前缀和操作。线段树(Segment Tree)为显式二叉树结构,支持区间查询与更新&a…

2026/7/29 1:22:04阅读更多 →
60、80、90、120法兰伺服电机如何匹配行星减速机框号?附计算与接口核对方法

60、80、90、120法兰伺服电机如何匹配行星减速机框号?附计算与接口核对方法

60、80、90、120法兰伺服电机如何匹配行星减速机框号?附计算与接口核对方法 “60法兰电机配060减速机,90法兰电机配090减速机”,是自动化行业中常见的快速匹配方法。 这套方法适合前期筛选,却不能作为最终订货依据。原因在于&…

2026/7/29 2:32:20阅读更多 →
PLF060-10-S2-P2型号含义详解:减速比、精度等级与电机接口怎么确认

PLF060-10-S2-P2型号含义详解:减速比、精度等级与电机接口怎么确认

PLF060-10-S2-P2型号含义详解:减速比、精度等级与电机接口怎么确认 PLF060-10-S2-P2是一类常见的伺服行星减速机型号。 从型号本身可以识别产品系列、减速机框号、减速比、输入配置和精度等级,但不能仅凭这串字符判断电机一定能够安装,也不能…

2026/7/29 2:32:20阅读更多 →
从广西洪涝看城市生命线的深层脆弱性

从广西洪涝看城市生命线的深层脆弱性

2026年7月,台风"美莎克"给广西带来了一场50年一遇的特大洪涝。59条河流超警、多座水库出险、5.5万人受灾——但这些数字背后,真正值得深究的,不是雨有多大,而是雨打在了一座什么样的城市上。本文以广西洪涝为剖面&#…

2026/7/29 2:32:20阅读更多 →
网络爬虫开发框架与反爬虫对抗技术全解析

网络爬虫开发框架与反爬虫对抗技术全解析

网络爬虫开发框架与反爬虫对抗技术全解析在当今信息爆炸的时代,网络数据已成为宝贵的资源。网络爬虫作为自动化获取网络信息的关键工具,其开发与反爬虫技术的对抗,构成了一场持续演进的技术博弈。这场博弈不仅关乎数据获取的效率与成本&#…

2026/7/29 2:32:20阅读更多 →
桌面级智能装置实战:绘图机、陀螺钟与太阳能追踪器设计全解析

桌面级智能装置实战:绘图机、陀螺钟与太阳能追踪器设计全解析

1. 项目概述:当创客精神遇上桌面级小玩意儿看到“迷你绘图机、创意旋转陀螺钟、微型太阳能追踪器”这个标题,很多老创客会心一笑,而刚入门的朋友可能会觉得眼花缭乱。这其实不是一个单一项目,而是一类项目的典型代表:桌…

2026/7/29 2:32:20阅读更多 →
OpenSmith:本地LLM Pipeline追踪与调试实战指南

OpenSmith:本地LLM Pipeline追踪与调试实战指南

在本地开发和调试 LLM 应用时,你是否遇到过这样的困境:想要追踪每个组件的输入输出、查看中间结果、分析性能瓶颈,却发现现有的工具要么需要接入云端服务,要么配置复杂、难以集成?特别是在涉及敏感数据或需要离线工作的…

2026/7/29 2:30:19阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/28 4:06:39阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/28 2:08:06阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/28 1:38:28阅读更多 →
28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“! 在构建复杂的 Agent 系统时,我们经常会遇到这样的场景:Agent 正在执行一个多步骤的任务,比如“下单购买商品”,但执行到一半时,我们…

2026/7/29 0:01:46阅读更多 →
自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

近日,国际专注开放式技术研发的声学品牌Nank南卡,正式官宣实力艺人曾舜晞担任品牌代言人。消息一经发出便轰动全网。为什么耳机品牌不选择流量明星、老牌歌手?而且是选择曾舜晞?让我们一起来探索一下!比起短期的流量&a…

2026/7/29 0:01:46阅读更多 →
【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:01:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/28 20:22:24阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/28 3:17:03阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/28 2:35:58阅读更多 →