使用Java网络编程,窗口,线程,IO,内部类等实现多人在线聊天1.0

1.整体思路

思路图

5b3c97a5649f45698a019a67b5c66527.png

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

 

TCP 协议

d1e074db85854c009a0f3ddcbb83c3cf.png

 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.启动服务器

16182041264b49778e2ebac0c2d25cf0.png

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

6c3652a6f8204a21a45bfd4673edef3c.png 5d985973b0ab475eaa8ff03c7b25195d.png

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

803003105bc245249faa05dd85651dfb.png

4.总结

本次聊天室1.0的简单实现使用了 Java 的网络编程 IO 线程 异常的抛出 集合 内部类 GUI等 

希望指出错误并提供改进意见 

 

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

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

相关文章

echart显示单个折线,其他折线隐藏

一开始去官方找文档。以为是series控制的&#xff0c;其实不是。 echart是通过legend控制哪个图显示和隐藏。 代码&#xff1a; legend: {show: true,left: center,selected: {折线1: true,折线2: false,折线3: false,}}, 配合series里面的name属性。控制折线的显示 serie…

Python---面向对象的综合案例

案例1&#xff1a;定义学员信息类&#xff0c;包含姓名、成绩属性&#xff0c;定义成绩打印方法&#xff08;90分及以上显示优秀&#xff0c;80分及以上显示良好&#xff0c;70分及以上显示中等&#xff0c;60分及以上显示合格&#xff0c;60分以下显示不及格&#xff09; 学员…

FPGA主芯片选型

硬件资源是器件选型的重要标准。 硬件资源包括逻辑资源、I &#xff0f; O 资源、布线资源、DSP 资源、存储器资源、锁相环资源、串行收发器资源和硬核微处理器资源等。 第一步&#xff1a;选定器件特色&#xff08;重点关注FPGA的专用资源&#xff09; 1、高速BANK的引脚 ①…

Stable Diffusion Automatic1111 Web UI和dreambooth扩展的安装教程

一 下载安装 Python 3.10.x (3.10.6, 3.10.9, 3.10.11) and git Python 3.10.9 > https://www.python.org/ftp/python/3.10.9/python-3.10.9-amd64.exegit > https://git-scm.com/downloads 二 下载安装Automatic1111 Web UI 下载地址&#xff1a;https://github.com/…

聚簇索引与非聚簇索引

聚簇索引与非聚簇索引 聚簇索引和非聚簇索引是数据库中常用的两种索引类型&#xff0c;它们的区别在于索引的顺序是否与数据的物理存储顺序一致。 聚簇索引&#xff1a; 聚簇索引的顺序就是数据的物理存储顺序&#xff0c;因此每张表只能有一个聚簇索引。聚簇索引的优点是查询…

封装校验规则(以及复选框和整体校验)-----Vue3+ts项目

登录校验页面 <script setup lang"ts"> import { ref } from vue import { mobileRules, passwordRules } from /utils/rules const mobile ref() const password ref() </script><!-- 表单 --><van-form autocomplete"off">&l…

2021年第十届数学建模国际赛小美赛A题气道阻力的评估解题全过程文档及程序

2021年第十届数学建模国际赛小美赛 A题 气道阻力的评估 原题再现&#xff1a; 气道阻力的定义是通过肺气道产生单位气流所需的经肺压力的变化。更简单地说&#xff0c;它是嘴和肺泡之间的压力差&#xff0c;除以气流。影响气道阻力的因素是多方面的&#xff0c;我们需要探讨这…

安卓发布小技巧

多个版本 apk多版本共存 如果是git多个分支&#xff0c;可只修改build.gradle里的applicationId。 SDK升级后缩包 Android M 的 NDK 行为变更对 APK 包体积的影响 安卓车载 Android车载开发与设备调试学习手册 tobecontinue…

imutils库介绍及安装学习

目录 介绍 本机环境 安装 常用函数 使用方法 图像平移 图像缩放 图像旋转 骨架提取 通道转换 OPenCV版本的检测 综合测试 目录 介绍 本机环境 安装 常用函数 使用方法 图像平移 图像缩放 图像旋转 骨架提取 通道转换 OPenCV版本的检测 介绍 imutils 是一…

目标检测综述(待补ing)

文章目录 摘要引言目标检测发展历程目标检测路线图传统检测器基于CNN的两阶段检测器基于CNN的一阶段检测器 目标检测数据集及指标数据集评价指标标注软件 backboneAlexNet&#xff08;2012&#xff09;VGGNet&#xff08;2014&#xff09;GoogleNet&#xff08;2014&#xff09…

如何统计12.5米高程覆盖率?

无论是卫星影像还是高程DEM数据&#xff0c;覆盖率都是大家非常关心的一个重要参数。 我们曾基于WGS84坐标进行过简单的覆盖率计算&#xff0c;而且面积还包括了海洋区域。 因此&#xff0c;最后得出了一个非常不靠谱&#xff0c;看起来也很不漂亮的数据&#xff1a;12%。 为…

Mysql主从集群搭建——基于docker-compose一键部署

搭建初衷 本身自己就是开发这类应用的工作者&#xff0c;一个私有库还是很有必要的。无论是公司项目还是私人项目都可以用到&#xff0c;不用担心忘记同步导致的数据丢失统一管理所有docker应用的数据&#xff08;如果容器可以连接mysql的话&#xff09;也方便随时修改数据结构…

hotkeys-js库实战记录 - 监听键盘按键(快捷键)

hotkeys-js 库&#xff0c;在npm上可搜索查找&#xff0c;作为自己项目里用来监听键盘快捷键&#xff0c;之前由领导负责的该功能模块&#xff0c;现闲来无事&#xff0c;看了下该库的文档&#xff0c;从头到尾跟着把所有API都测了一遍。 特性概览&#xff1a; 监听键盘按键(快…

Python实现广义线性回归模型(statsmodels GLM算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 广义线性模型(Generalized Linear Model&#xff0c;简称GLM)是一种广泛应用于回归分析和分类问题的统…

[足式机器人]Part2 Dr. CAN学习笔记-数学基础Ch0-4线性时不变系统中的冲激响应与卷积

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-数学基础Ch0-4线性时不变系统中的冲激响应与卷积 1. LIT System&#xff1a;Linear Time Invariant2. 卷积 Convolution3. 单位冲激 Unit Impulse——Dirac Delta 线性时不变系统 &#xff1a; L…

Science | 张锋实验室:聚类算法揭示188种新型CRISPR系统

微生物序列数据库包含大量有关酶和其他可用于生物技术的分子的信息。但近年来&#xff0c;这些数据库已经变得非常庞大&#xff0c;以至于很难有效地搜索到感兴趣的酶。 2023年11月23日&#xff0c;博德研究所张锋及美国国立卫生研究院Eugene V. Koonin共同通讯在Science 在线…

软件测试外包干了2个月,技术进步2年。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;18年通过校招进入北京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

01_W5500简介

目录 W5500简介&#xff1a; 芯片特点: 全硬件TCPIP协议栈: 引脚分布&#xff1a; W5500简介&#xff1a; W5500是一款高性价比的以太网芯片&#xff0c;其全球独一无二的全硬件TCPIP协议栈专利技术&#xff0c;解决了嵌入式以太网的接入问题&#xff0c;简单易用&#xff…

【WPF】弹出一个弹窗并显示一个列表

要在WPF中弹出一个弹窗并显示一个列表&#xff0c;你可以使用Popup元素和一个包含列表的控件&#xff0c;如ListBox或ListView。下面是一个示例&#xff1a; <Grid><Button Content"打开弹窗" Click"Button_Click" /><Popup x:Name"P…

CasADi - 最优控制开源 Python/MATLAB 库

系列文章目录 文章目录 系列文章目录前言一、介绍1.1 CasADi 是什么&#xff1f;1.2 帮助与支持1.3 引用 CasADi1.4 阅读本文档 二、获取与安装三、符号框架3.1 符号 SX3.1.1 关于命名空间的说明3.1.2 C 用户注意事项 3.2 DM3.3 符号 MX3.4 SX 和 MX 混合使用3.5 稀疏类3.5.1 获…