Java—简易聊天室

article/2025/10/23 5:16:41

Java—聊天室的实现

在学习了IO流,多线程以及网络编程的知识之后,我们可以利用所学到的知识做一个小项目,这里我做了一个多人聊天室,实现了群聊和私聊功能,看完分享之后也可以自己去做一个练练手。

首先是整个项目的大体架构:首先要分为服务器端和客户端两个端口。如下图所示

image.png

客户端可以向服务器发送信息,并接受服务器返回的信息。而服务器实际上是作为一个中转站:在群聊模式时,将一个客户端的发送的信息转发至其他客户端。而在私聊时,服务器将信息发送到指定的客户端处,达到私聊的效果。

我们先依次附上服务器端与客户端的代码,再讲解实现的具体过程

服务器端(这里用本地主机作为服务器):

public class Server {private List<MyChannel> all = new ArrayList<MyChannel>();public static void main(String[] args) throws IOException {new Server().start();}public void start() throws IOException {ServerSocket server = new ServerSocket(7777);while(true) {Socket client = server.accept();MyChannel channel = new MyChannel(client);all.add(channel);new Thread(channel).start();        //一条道路}}/*** 一个客户一条道路* 建立服务器与客户端之间的数据通道**/private  class MyChannel implements Runnable {private DataInputStream dis;private DataOutputStream dos;private boolean flag = true;private String name;public MyChannel(Socket client) {try {dis = new DataInputStream(client.getInputStream());dos = new DataOutputStream(client.getOutputStream());} catch (IOException e) {e.printStackTrace();flag = false;try {dis.close();dos.close();} catch (IOException e1) {e1.printStackTrace();}}}//接收客户端的信息private String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {flag = false;e.printStackTrace();all.remove(this);try {dis.close();} catch (IOException e1) {e1.printStackTrace();}}return msg;}//向客户端发送信息private void send(String msg) {if (null == msg || msg.equals("")) {return;}try {dos.writeUTF(time());dos.writeUTF(msg);} catch (IOException e) {flag = false;e.printStackTrace();all.remove(this);  //移除自身try {dos.close();} catch (IOException e1) {e1.printStackTrace();}}}private void sendOthers(String msg) {//判断是否是私聊if (msg.contains("@") && msg.indexOf(":") > msg.indexOf("@")){String spot = null;String secreName = msg.substring(msg.indexOf("@") + 1, msg.indexOf(":"));String secretMsg = msg.substring(msg.indexOf(":") + 1);
//                System.out.println(secreName);
//                System.out.println(secretMsg);for (MyChannel other : all) {if (secreName.equals(other.name)) {other.send(name + "悄悄地对你说:" + secretMsg);}}}else{for (MyChannel other : all) {if (other == this) {continue;}other.send(msg);}}}private String time () {Date now = new Date(System.currentTimeMillis());String time = new SimpleDateFormat("yyyy.MM.dd  hh:mm:ss").format(now);return time;}@Overridepublic void run () {send("欢迎加入群聊");name = receive();sendOthers(name + "加入了群聊");while (flag) {sendOthers(receive());}}}}

现在我们来分析这段代码

  • 1> 首先,Server类中包含一个ArrayList容器,其中保存的是MyChannel类元素,实际上每一个MyChannel类的对象就是一条 连接服务器与客户端的路径(其中数据以流的形式传输)
  • 2> 在主函数中实例化了Server对象之后,调用了start()方法,我们看到方法体中首先为服务器端创建了ServerSocket对象,并指定了端口。紧接着就是一个死循环,接受连接到服务器的客户端,并将其信息添加至ArrayList容器中,并为其创建一条线程(线程就绪并开始运行)
  • 3> 那么MyChannel类内部又是什么呢?我们画图来分析
    image.png
  • 4> 构造器:只有一个以Socket类的客户端对象为参数的构造器,在该构造器中,传入了客户端对象后,建立于客户端对象的数据通道。
  • 5> receive()方法:从数据通道中读取从客户端发送来的信息(字符串)
  • 6> time()方法:生成当前的具体时间,并以字符串形式返回
  • 7> send(String msg)方法:将time()与msg信息依次发送到客户端
  • 8> sendOthers(String msg):私聊部分(私聊形式:@客户端名:私聊信息):先对传入的msg进行分析,若字符串首字符为 ‘@’ 并且字符串中含有 ‘:’时,即判断这条信息是一条私聊信息,将私聊客户端名与私聊内容从msg中分离出来,并将其单独发送给指定的客户端(遍历容器并匹配客户端名)。群聊部分(直接发送内容):遍历整个容器,除了当前客户端,向其他所有客户端发送消息。
  • 9> 线程体部分(run()方法 ):在一个客户端接入服务器后,首先向其发送一条”欢迎加入群聊”的信息,再将其加入聊天室的信息发送给其他聊天室内的用户,然后执行死循环 sendOthers(receive()) 方法

客户端(包含三个类):

  • 客户端类:
public class Client {public static void main(String[] args) throws IOException {System.out.println("请输入昵称");BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String name = br.readLine();Socket client = new Socket("localhost",7777);//客户端发送new Thread(new Send(client,name)).start();//客户端接收new Thread(new Receive(client)).start();}}

我们对客户端代码进行分析:

  • Client 类中只有一个主方法,刚开始会要求你为客户端起名,紧接着创建Socket类实例,并与本地服务器的指定端口连接。
  • 多线程的问题:我们不能规定客户端是先读取再发送还是先发送再读取,所以为两个功能分别建立一条线程,即读与写可以同时实现,而接受和发送信息的类就是下面要说的Receive类和Send类

  • Receive类:
public class Receive implements Runnable{//输入流private DataInputStream dis;//线程标识,判断线程运行状态private boolean flag = true;public Receive(Socket client){try {dis = new DataInputStream(client.getInputStream());} catch (IOException e) {e.printStackTrace();flag = false;try {dis.close();} catch (IOException e1) {e1.printStackTrace();}}}//接收数据public String receive(){String msg = "";try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();flag = false;try {dis.close();} catch (IOException e1) {e1.printStackTrace();}}return msg;}@Overridepublic void run() {while(flag){System.out.println(receive());}}
}
  • Receive类是负责接收从服务器发来的消息的类,主要有三个地方使用:1.刚与服务器连接后服务器发来的欢迎信息的接收。2.群聊信息的接收(时间+内容)。3.私聊信息的接收(时间+私聊内容)
  • receive()方法,从输入流中读取信息。
  • 线程体(run()方法):只有一个始终接收信息并打印到控制台的循环体

  • Send 类:
public class Send implements Runnable{//控制台输入流private BufferedReader console;//管道输出流private DataOutputStream dos;//控制线程private boolean flag= true;//聊天昵称private String name;public Send() {console = new BufferedReader(new InputStreamReader(System.in));}public Send(Socket client,String name){this();this.name = name;try {dos = new DataOutputStream(client.getOutputStream());} catch (IOException e) {//e.printStackTrace();flag = false;}}//从控制台接收数据private String getMsgFromConsole() {try {return console.readLine();} catch (IOException e) {e.printStackTrace();}return "";}//发送数据public void send(String msg){if (null != msg && !msg.equals("")){try {dos.writeUTF(name +": " + msg);Date now = new Date(System.currentTimeMillis());String time = new SimpleDateFormat("hh:mm:ss   yyyy/MM/dd  ").format(now);System.out.println(time);System.out.println(name + ":" + msg);dos.flush();} catch (IOException e) {e.printStackTrace();try {flag = false;dos.close();console.close();} catch (IOException e1) {e1.printStackTrace();}}}else{try {dos.writeUTF(name);} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void run() {//线程体send("");while (flag){send(getMsgFromConsole());}}
}
  • Send类负责从控制台读入客户端所输入的信息,并将信息发送至服务器,由服务器判断是私聊信息还是群聊信息。
  • 构造器:有一个无参构造器和一个参数为客户端对象和客户端名的构造器,建立对服务器的数据输出流,并保存客户端名
  • 线程体(run()方法):先发送一个空字符串,send()方法会自动判断为发送客户端名至服务器,然后再循环体中始终执行发送从控制台读取的字符至服务器的方法
  • send()方法:初次发送时,会将客户端名发送至服务器,在之后将从控制台读取信息并发送至服务器,同时在自己的控制台上打印自己发送消息的时间和消息的内容

调试结果

在IDEA 的控制台上运行服务器,将客户端类打jar包在本地Powershell上运行

image.png

  • 第一个客户端接入:
    image.png

  • 服务器控制台信息:
    image.png

  • 多个客户端接入
    image.png

  • 服务器控制台信息:
    image.png

  • 群聊实现:
    image.png

  • 私聊实现:
    image.png

功能还是都能实现的,可能会有一些小Bug,界面也没有做出来,不过主要是为了综合前面所学到的知识并去运用


http://chatgpt.dhexx.cn/article/vWKm63Pu.shtml

相关文章

java聊天室(实训项目)

这里是我们实训的一个关于java聊天室的项目&#xff0c;有需要的同学可以看看&#xff0c;私聊功能未完善。 话不多说&#xff0c;直接上代码。 服务器&#xff1a; package ChatRoom;import java.awt.Color; import java.awt.Component; import java.awt.EventQueue; impor…

Java实现简易聊天室

Java实现简易聊天室 在学习《Java从入门到精通》这本书&#xff0c;网络通信&#xff0c;基于TCP实现的简易聊天室&#xff0c;我这里对书中的代码略做了修改&#xff0c;做个记录。 这里先放一下运行效果图&#xff0c;代码放在最后。 运行效果&#xff1a; 先启动服务器端&am…

javaWeb实现聊天室(私聊+群聊)

写在前面 近几天&#xff0c;迎来了第一个小项目&#xff0c;不做不知道&#xff0c;一做吓一跳。好多知识都掌握的不够扎实&#xff0c;看似会了&#xff0c;但其实似懂非懂&#xff0c;不能真正掌握原理&#xff0c;导致使用起来错误百出。而且深深体会到&#xff0c;知识只有…

java实现聊天室(GUI界面+私聊+群聊)

登录界面的用户名和端口号不能重复&#xff01; 登录界面的用户名和端口号不能重复&#xff01; 登录界面的用户名和端口号不能重复&#xff01; java的socket编写的聊天室&#xff0c;GUI的界面&#xff0c;可以私聊和群聊&#xff0c; 聊天信息保存为txt 有需要的可以自行下…

用Java代码实现一个简单的聊天室功能

一.客户端的创建 1.我们可以用Socket来创建客户端 /***类名 Client*描述 TODO 客户端 1*版本 1.0*创建人 XuKang*创建时间 2020/9/24 16:18**/ public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println(…

Java在线聊天室(客户端+服务器)

Java在线聊天室&#xff08;客户端服务器&#xff09;基于webSocket实现模拟在线聊天系统 运行环境&#xff1a; JDK1.8version 开发环境&#xff1a;Eclipse 一、结构 以下是系统主要结构&#xff1a; 1.用户&#xff08;均实现部分可能会有bug&#xff09; &#xff08;…

apiDay09整理笔记(笔记优化)

目录 1.聊天室&#xff08;续&#xff09; &#xff08;1&#xff09;实现服务端发送消息给客户端 &#xff08;2&#xff09;服务端转发消息给所有客户端 &#xff08;3&#xff09;客户端解决收发消息的冲突问题 &#xff08;4&#xff09;服务端完成处理客户端断开连接…

JAVA简单聊天室的实现

目录 界面效果图 一、聊天室功能介绍&#xff1f; 二、功能代码 1.服务端 2.客户端 界面效果图 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、聊天室功能介绍&#xff1f; 1. 、对于聊天室就是处理多个客户端发送的请求与信息&#xff0c;从…

Java网络聊天室---个人博客

Java网络聊天室 ———个人博客 一、项目简介 功能描述&#xff1a; 使用图形用户界面和socket通信&#xff0c;能实现一个聊天室中多人聊天&#xff0c;可以两人私聊&#xff0c;可以发送文件。 实现类似QQ用户注册、登录、聊天等功能。 参考git地址或博客地址&#xff1a…

Java实现ChatRoom

基于连接通信Socket、多线程的Java聊天室 1、开发环境&#xff1a; IDEA2018.1JDK1.8 2、实现功能&#xff1a; 实现了模拟登录注册、群聊、私聊、显示当前在线人数列表&#xff1b; 在发送信息时&#xff0c;会向对方发送者及显示发送时间&#xff1b; 显示在线人数列表…

Java聊天室

项目介绍&#xff1a; Java聊天室是期末设计&#xff0c; 阿里巴巴druidmysql多线程GUImvn项目java Socket 服务端模块&#xff1a;踢出聊天室&#xff1a;管理员可以踢出发言不当的用户。只有当开启服务端的时候&#xff0c;客户端才能起到作用。 客户端模块&#xff1a; 注册…

用Java实现简易聊天室

说明&#xff1a;如果一个 类&#xff0c;需要有界面的显示&#xff0c;那么该类就需要继承自JFrame&#xff0c;此时&#xff0c;该类就可以被称为一个“窗体类"。 服务端代码&#xff1a; package cn.qy.chat;import javax.swing.*; import java.awt.*; import java.aw…

微信小程序购物车功能实现(干货满满)

微信小程序定制好看的购物车页面&#xff0c;实现购物车功能&#xff0c;希望对您有所帮助&#xff01; 1. 应用场景 2. 思路分析 3. 代码分析 4. 具体实现代码 效果截图&#xff1a; 1.应用场景 适用于商城、秒杀、商品购买等类型的小程序&#xff0c;负责将顾客浏览的商…

微信小程序微商城(八):缓存实现商品购物车功能

IT实战联盟博客&#xff1a;http://blog.100boot.cn 上一篇&#xff1a;微信小程序微商城&#xff08;七&#xff09;&#xff1a;动态API实现商品分类 看效果 购物车.gif 开发计划 1、商品详情页将商品信息放入缓存 2、购物车页面读取缓存获取商品信息 3、购物车商品计算…

微信小程序开发一个小型商城(六、购物车页面)

上一篇文章&#xff1a;微信小程序开发一个小型商城&#xff08;五、商品详情&#xff09; 当我们在商品详情界面中点击添加购物后&#xff0c;会跳转到购物车界面&#xff0c;购物车界面是一个tabbar&#xff0c;在跳转的时候需要加上ope-type。看下购物车的静态页面把&#x…

微信小程序实现一个购物车页面的简易列表效果

本文只是简单的模仿天猫APP的购物车列表的样式效果&#xff0c;并实现了部分事件功能&#xff0c;功能并不完善&#xff0c;请降低期待观看。 天猫APP的购物车效果&#xff1a; 小程序模仿的实现效果&#xff1a; wxml部分的代码&#xff1a; <view wx:if"{{!isCartEmp…

【Python之pymysql库学习】一、分析fetchone()、fetchmany()、fetchall()(保姆级图文+实现代码)

目录 实现效果实现思路实现代码总结 欢迎关注 『Python之pymysql库学习』 系列&#xff0c;持续更新中 欢迎关注 『Python之pymysql库学习』 系列&#xff0c;持续更新中 实现效果 实现思路 其实有半数代码是创建数据库和创建数据表并插入数据这些环境配置部分我都写好了&…

fetchone、fetchall

fetchone(): 该方法获取下一个查询结果集。结果集是一个对象,读取一行结果&#xff0c;读取完指向下一行&#xff0c;到空为止 fetchall():接收全部的返回结果行&#xff0c;到空为止 fetchone() &#xff1a; 返回单个的元组&#xff0c;也就是一条记录(row)&#xff0c;如果没…

python fetchall方法_Python连接MySQL并使用fetchall()方法过滤特殊字符

python3.3从mysql里取出的数据莫名其妙有括号和逗号每天跟自己喜欢的人一起&#xff0c;通电话&#xff0c;旅行&#xff0c;重复一个承诺和梦想&#xff0c;听他第二十八次提起童年往事&#xff0c;每年的同一天和他庆祝生日&#xff0c;每年的情人节圣诞节除夕&#xff0c;也…

pdo fetchAll

作用 fetchAll()方法是获取结果集中的所有行.其返回值是一个包含结果集中所有数据的二维数组。 PDOStatement::fetchAll ([ int $fetch_style [, mixed $fetch_argument[, array$ctor_args array() ]]] ) fetch_style:控制结果的返回方式 PDO::FETCH_ASSOC 关联数组形式 PD…