使用Java网络编程,窗口,线程,IO,内部类等实现多人在线聊天1.0
1.整体思路
思路图

整体思路如上: 涉及知识点:线程+网络编程+集合+IO等
TCP 协议

2.代码实现过程
服务端
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;public class Server extends JFrame {//继承窗口来实现窗口功能/*设置接受客户端的集合,把接入服务器的客户端存入集合,方便后续的消息转发*/ArrayList<Socket> socketsClients = new ArrayList<>();/*由于下面线程需要调用窗口的一些东西,所以需要全局变量*/JTextArea jTextArea;JTextArea jTextSend = new JTextArea(30,20);//只能设置几列JButton jButtonSend = new JButton("发送") ;public Server() {//创建服务器窗口 一些列属性//主面板JPanel priorPanel = new JPanel(new BorderLayout());//显示消息this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭窗口结束程序this.setTitle("来自客户端的消息");this.setSize(500, 500);jTextArea = new JTextArea();//显示客户端的信息jTextArea.setEditable(false);//不可以修改 面板信息JScrollPane clientInformation = new JScrollPane(jTextArea);priorPanel.add(clientInformation,BorderLayout.CENTER);//写一个发布公告的窗口JPanel sendPanel = new JPanel();//默认流式布局JScrollPane jScrollPane = new JScrollPane(jTextSend);jScrollPane.setPreferredSize(new Dimension(400,50));sendPanel.add(jScrollPane);sendPanel.add(jButtonSend);priorPanel.add(sendPanel,BorderLayout.SOUTH);this.add(priorPanel);//创建监听发送键 jButtonSend.addActionListener(new ActionListener() {/*用来对每个客户端发送公告*/@Overridepublic void actionPerformed(ActionEvent e) {String announcement = "来自服务器的公告:"+jTextSend.getText()+"\n";//把公告发布到聊天界面jTextArea.append(announcement);/*使用for循环来遍历每个客户端的对象*/for(Socket soc:socketsClients){DataOutputStream dataOutputStream = null;try {dataOutputStream = new DataOutputStream(soc.getOutputStream());dataOutputStream.writeUTF(announcement+"\n");} catch (IOException ioException) {ioException.printStackTrace();}}jTextSend.setText(null);}});this.setVisible(true);
//===================================================================================
//以上为窗口的创建,下面为功能的实现try {//创建服务器对象 设置端口ServerSocket serverSocket = new ServerSocket(9998);//使用无限循环来不停接受客户端的连接while(true){Socket socketClient = serverSocket.accept();//接收到一个就向集合加入一个客户端socketsClients.add(socketClient);//就收一个连接就在后台提示一遍System.out.println("有"+socketsClients.size()+"个邓钦文连接到服务器!");//然后启动该客户端的线程 线程的实现则需要我们使用内部类new SocketThread(socketClient).start();}//处理客户端输入的东西} catch (IOException e) {e.printStackTrace();System.out.println("服务器启动失败!");}}//创建监听//创建内部类 线程class SocketThread extends Thread{DataInputStream dataInputStream;Socket socket;/*构建方法 传入当前客户的连接*/public SocketThread(Socket socket) throws IOException {/*接受客户端的输入流*/dataInputStream = new DataInputStream(socket.getInputStream());this.socket = socket;}/*重写run方法 来实现对客户端的操作方法*/@Overridepublic void run() {while(true){try {String msg = dataInputStream.readUTF();/*读取客户端的信息 并打印到自己的窗口上*/jTextArea.append(msg+"\n");//给每一个客户端发送信息 实现群聊的效果for(Socket soc:socketsClients){DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream());dataOutputStream.writeUTF(msg+"\n");}} catch (IOException e) {e.printStackTrace();System.out.println("读取失败!");socketsClients.remove(socket);return;}}}}}
客户端
登录界面
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;public class EnterFrame extends JFrame {public EnterFrame() throws HeadlessException {this.setSize(600,500);this.setTitle("欢迎登录");this.setResizable(true);this.setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭窗口结束程序this.setLocationRelativeTo(this);JPanel jPanelLast = new JPanel(new GridLayout(4,1));//头顶部分JPanel jPanelTop = new JPanel();JLabel jLabel = new JLabel("欢迎登录");jLabel.setFont(new Font("宋体",Font.BOLD,30));//中间部分JPanel jPanelMiddle = new JPanel(new GridLayout(2,1,0,0));JPanel jPanelAccount = new JPanel(new FlowLayout());//账号密码输入端JLabel jLabelAccount = new JLabel("账号");JTextField jTextFieldAccount = new JTextField(15);jPanelAccount.add(jLabelAccount);jPanelAccount.add(jTextFieldAccount);JPanel jPanelPassword = new JPanel(new FlowLayout());JLabel jLabelPassword = new JLabel("密码");JPasswordField jTextFieldPassword = new JPasswordField(15);jPanelPassword.add(jLabelPassword);jPanelPassword.add(jTextFieldPassword);//底部 登录按钮端JPanel jPanelFoot = new JPanel();JPanel jPanelButton = new JPanel(new FlowLayout());JButton enterButton = new JButton("登录");JButton signButton = new JButton("注册");jPanelButton.add(enterButton);jPanelButton.add(signButton);jPanelTop.add(jLabel);jPanelMiddle.add(jPanelAccount);jPanelMiddle.add(jPanelPassword);jPanelFoot.add(jPanelButton);jPanelLast.add(jPanelTop);jPanelLast.add(jPanelMiddle);jPanelLast.add(jPanelFoot);this.add(jPanelLast);this.setVisible(true);
//================================================================================
//以上为登录界面窗口的设计 可以自己设计//设计监听事件 来判断用户的读取enterButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {
//1.判断不能为空if(jTextFieldAccount.getText().length()<=0||jTextFieldPassword.getText().length()<=0) {JOptionPane.showMessageDialog(null, "输入的账号或密码为空!");return;}
//2.输入只能为数字与字母if((jTextFieldAccount.getText().matches("[a-zA-Z0-9]*")&&jTextFieldPassword.getText().matches("[a-zA-Z0-9]*"))==false){JOptionPane.showMessageDialog(null,"输入的账号或密码只能为字母和数字");return;}//如果都满足了登录成功 创建 客户端对象 输入服务器地址 与端口 关闭登录界面try {Socket socket = new Socket("127.0.0.1", 9998);new ChatFrame(jTextFieldAccount.getText(),socket);dispose();//关闭了登录窗口} catch (IOException ioException) {ioException.printStackTrace();JOptionPane.showMessageDialog(null,"无法连接服务器");}}});}}
聊天界面
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;public class ChatFrame extends JFrame {JTextArea jTextArea;public ChatFrame(String account , Socket socket) throws HeadlessException {this.setSize(700, 600);this.setTitle("欢迎来到"+account+"聊天室");this.setResizable(true);this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);JPanel jPanelEnd = new JPanel( new BorderLayout());//最终面板jTextArea = new JTextArea();jTextArea.setEditable(false);JScrollPane jScrollPane1 = new JScrollPane(jTextArea);jPanelEnd.add(jScrollPane1,BorderLayout.CENTER);JPanel jPanelInput = new JPanel();JTextArea jTextArea2 = new JTextArea(5,40);//带滑动的窗口JScrollPane jScrollPane2 = new JScrollPane(jTextArea2);//不能通过add加入,只能通过构造方法加入,这样不会出现不显示的问题jPanelInput.add(jScrollPane2);JButton jButtonSend = new JButton("发送");jPanelInput.add(jButtonSend);jPanelEnd.add(jPanelInput,BorderLayout.SOUTH);this.add(jPanelEnd);try {new ClientThread(socket).start();} catch (IOException e) {e.printStackTrace();JOptionPane.showMessageDialog(null,"发送错误");}
//关闭窗口,显示登录窗口this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.out.println("你确定要关闭我妈?");int res = JOptionPane.showConfirmDialog(null,"你确定要关闭我吗","操作提示",JOptionPane.OK_CANCEL_OPTION);if(res==0){//点击确定new EnterFrame();dispose();//关闭当前对象}}});//监听发送事件try {DataOutputStream socketOutput = new DataOutputStream(socket.getOutputStream());String message = socketOutput.toString();jButtonSend.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if(message.length()<=0){JOptionPane.showMessageDialog(null,"输入消息不能为空!");return;}String msg = account+" "+ new SimpleDateFormat("yyyy-MM HH:mm:ss").format(new Date()) +"\n"+jTextArea2.getText();try {socketOutput.writeUTF(msg);System.out.println(msg);jTextArea2.setText("");} catch (IOException ioException) {ioException.printStackTrace();JOptionPane.showMessageDialog(null,"发生错误");}}});} catch (IOException e) {e.printStackTrace();}this.setVisible(true);
//=======================================================================================
//窗口的创建以及窗口功能的实现}//创建内部列 创建客户端的线程,解决多个聊天窗口同时实现class ClientThread extends Thread{DataInputStream inputStream;Socket socket;/*构造方法*/public ClientThread(Socket socket) throws IOException {inputStream = new DataInputStream(socket.getInputStream());this.socket = socket;}@Overridepublic void run() {try {while(true){/*把接受的到信息添加到窗口中*/String msg = inputStream.readUTF();jTextArea.append(msg+"\n");}} catch (IOException e) {e.printStackTrace();return;}}}
}
启动程序
public class RunOfServer {public static void main(String[] args) {new Server();}
}
public class RunOfClient {public static void main(String[] args) {new EnterFrame();}
}
3.实现结果
1.启动服务器

2.尝试启动 3个客户端 并登录

3.测试消息发送接收以及公告发送功能.

4.总结
本次聊天室1.0的简单实现使用了 Java 的网络编程 IO 线程 异常的抛出 集合 内部类 GUI等
希望指出错误并提供改进意见
相关文章:
使用Java网络编程,窗口,线程,IO,内部类等实现多人在线聊天1.0
1.整体思路 思路图 整体思路如上: 涉及知识点:线程网络编程集合IO等 TCP 协议 2.代码实现过程 服务端 import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import jav…...
相关教程test
第一天 主题:LLM初体验 上午: 一,大模型的发展背景和模型演进 数据增长和算力提升LSTM到BERT到LLM的参数巨变最新paper解读(根据授课时间,选择最近的核心paper进行解读) 二,大模型核心阶段…...
mysql知识分享(包含安装卸载)(一)
如果博客有错误,请佬指正。 目录 注意:打开cmd时要有管理员身份打开,重要 为何使用数据库? 数据库的相关概念 关系型数据库 关系型数据库设计规则 表,记录,字段 表的关联关系 一对一关联 一对多关系 …...
Google Guava 反射工具使用详解
文章目录 反射类操作方法操作字段操作获取注解 反射 在 Guava 中,反射(Reflection)模块提供了一些用于简化反射操作的工具类和方法。通过 Guava 的反射模块,您可以方便地进行类、方法、字段的操作、获取注解信息等。下面详细介绍…...
MySql MVCC 详解
注意以下操作都是以InnoDB引擎为操作基准。 一,前置知识准备 1,MVCC简介 MVCC 是多版本并发控制(Multiversion Concurrency Control)的缩写。它是一种数据库事务管理技术,用于解决并发访问数据库的问题。MVCC 通过创…...
工业机器视觉megauging(向光有光)使用说明书(三,轻量级的visionpro)
下来我们说说第二个相机的添加: 第一步,点击相机二,如下: 第二步,点击:加载工具组.xml,加载toolgroupxml2目录下的:工具组.xml 注意,一个相机只能用一个toolgroupxml,第…...
Linux 环境下,jdbc连接mysql问题
1. 下载MySQL的JDBC驱动: 从MySQL官网下载最新的MySQL Connector/J,并将其解压到某个目录,比如/usr/local/mysql/。 2. 将JDBC驱动添加到类路径: 将JDBC驱动添加到类路径,可以使用以下命令: export CLA…...
Python读写txt文件数据
🎈 博主:一只程序猿子 🎈 博客主页:一只程序猿子 博客主页 🎈 个人介绍:爱好(bushi)编程! 🎈 创作不易:如喜欢麻烦您点个👍或者点个⭐! …...
Linux虚假唤醒
为什么会有虚假唤醒一说。Linux内核这么强大,怎么会出现这样的情况?一直以来也很困惑,看了下文链接中的介绍后,豁然开朗。 从计算机设计的角度,如果一层解决不了,那就再多加一层。推算到这里,就…...
倒计时模块复习
经典回顾倒计时 倒计时的基本布局介绍。 一个内容区域和一个输入区域,内容区域进行划分 直接使用flex布局会更快一点。 js代码 我们利用一下模块化思想,直接把获得时间这个功能写成一个函数。方便后续的调用 function getTime() {const date new Date…...
k8s(三): 基本概念-ReplicaSet与Deployment
PeplicaSet ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合,通常用来保证给定数量的、完全相同的 Pod 的可用性。 最佳实践 Deployment 是一个可以拥有 ReplicaSet 并使用声明式方式在服务器端完成对 Pod 滚动更新的对象。 尽管 Rep…...
Linux 的介绍和云服务器上web 程序部署
目录 一.linux的介绍 1.1linux是什么 1.2linux的发展历程 1.3linux发行版 二.Linux环境搭建 2.1阿里云-云服务器配置 2.2使用终端软件连接Linux 三.操作Linux,部署web程序 3.1Linux指令 3.2部署web程序 第一步:认识yum 第二步:安装…...
Oauth2.0 学习
OAuth 2.0 服务器端通常通过验证每次请求中的访问令牌(access token)的方式来确保其合法性和有效性。以下是一些通常采用的验证方法: Token Validation Endpoint: OAuth 2.0 规范允许实现一个专门的令牌验证端点,称为 Token Valid…...
Elasticsearch:什么是向量数据库?
向量数据库定义 向量数据库是将信息存储为向量的数据库,向量是数据对象的数值表示,也称为向量嵌入。 它利用这些向量嵌入的强大功能来对非结构化数据和半结构化数据(例如图像、文本或传感器数据)的海量数据集进行索引和搜索。 向…...
rename--统一的PRF
基本概念 将ARF/PRF进行合并,合同之后的不见,称之为统一的PRF(Physical Register File);存储的是speculative的,以及正确的(retire)寄存器值; 使用free list,存储PRF中,哪些寄存器是…...
010-editor破解(1)
查看字符串 使用rabin2 -z /home/burning/010editor/010editor | tee 22.txt 查看字符串。 6698 0x003ba380 0x007ba380 68 69 .rodata ascii The password you entered is for an earlier version of this program. 6699 0x003ba3c8 0x007ba3c8 70 71 .rodata ascii You will…...
Ubuntur编译ROS报错:error PCL requires C++14 or above
ubuntu20.04 编译ROS包 报错: error: PCL requires C14 or above: 修改Cmakelists.txt文件: set(CMAKE_CXX_STANDARD 14) 再次编译成功....
17.认识下Docker之docker的核心原理(2)
1.容器-我的小世界 不知道大家看没看过小说《完美时间》,里面石昊经常进入一个小世界在里面与世隔绝的修炼或者战斗,总之就是在一个完全封闭的空间里做他想做的事情而与外界隔离,不受侵扰。通过前面的分析我们知道,Namepace让应用…...
【EasyExcel实践】万能导出,一个接口导出多张表以及任意字段(可指定字段顺序)
文章目录 前言正文一、POM依赖二、核心Java文件2.1 自定义表头注解 ExcelColumnTitle2.2 自定义标题头的映射接口2.3 自定义有序map存储表内数据2.4 表头工厂2.5 表flag和表头映射枚举2.6 测试用的实体2.6.1 NameAndFactoryDemo2.6.2 StudentDemo 2.7 启动类2.8 测试控制器 三、…...
代码随想录算法训练营第四十二天 _ 动态规划_01背包问题、416.分割等和子集。
学习目标: 动态规划五部曲: ① 确定dp[i]的含义 ② 求递推公式 ③ dp数组如何初始化 ④ 确定遍历顺序 ⑤ 打印递归数组 ---- 调试 引用自代码随想录! 60天训练营打卡计划! 学习内容: 二维数组处理01背包问题 听起来…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
