分析:
聊天室需要多个客户端和一个服务端。
服务端负责转发消息。
客户端可以发送消息、接收消息。

消息分类:群聊消息:发送除自己外所有人私聊消息:只发送@的人系统消息:根据情况分只发送个人和其他人
技术方面:客户端和服务端收发消息,需要使用IO流,封装一个IOUtils工具类用来释放资源。客户端需要同时收发消息,需要启动发送和接收两个消息,互不干扰服务端需要接收每个客户端消息和对多个客户端发送消息,每连接上一个客户端需要启动一个线程,让后面进来的客户端不需要等待前面的客户端退出后才能建立连接。

……

还是上代码吧。

基础版:

搭建结构,实现多个客户端和服务端连接,保证服务端能正常转发消息。
我们约定:
当服务端在初始化、发送、接收时出现异常时分别输出:
------1------
------2------
------3------

当客户端,初始化发送线程、初始化接收线程、发送、接收异常时分别输出:
======1=====
======2=====
======3=====
======4=====

1、IO工具类

package com.xzlf.chat;import java.io.Closeable;
import java.io.IOException;/*** 工具类* @author xzlf**/
public class IOUtils {/*** 释放资源* @param closeables*/public static void close(Closeable...closeables) {for (Closeable closeable : closeables) {if(null != closeable) {try {closeable.close();} catch (IOException e) {e.printStackTrace();}}}}
}

2、服务端

package com.xzlf.chat;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;/*** 聊天室:服务器* @author xzlf**/
public class TMultiChat {public static void main(String[] args) throws IOException {System.out.println("======server======");// 1、指定端口创建服务端ServerSocket server = new ServerSocket(8888);while(true) {// 2、每进来一个客户端启动一个线程Socket socket = server.accept();System.out.println("一个客户端建立了连接");new Thread(new Channel(socket)).start();}}// 一个Channel 代表一个客户端static class Channel implements Runnable{private Socket socket;private DataInputStream dis;private DataOutputStream dos;private boolean isRuning;public Channel(Socket socket) {this.socket = socket;this.isRuning = true;try {dis = new DataInputStream(socket.getInputStream());dos = new DataOutputStream(socket.getOutputStream());} catch (IOException e) {System.out.println("------1------");this.release();}}// 接收消息private String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {System.out.println("------3------");this.release();}return msg;}// 发送消息private void send(String msg) {try {dos.writeUTF(msg);} catch (IOException e) {System.out.println("------2------");this.release();}}// 释放资源private void release() {this.isRuning = false;IOUtils.close(dis, dos, socket);}@Overridepublic void run() {while(isRuning) {String msg = this.receive();if (!msg.equals("")) {this.send(msg);}}}}
}

3、多线程封装发送端

package com.xzlf.chat;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream.GetField;
import java.net.Socket;/*** 利用多线程封装发送端* * @author xzlf**/
public class Send implements Runnable{private Socket socket;private DataOutputStream dos;private BufferedReader console;private boolean isRuning;public Send(Socket socket) {this.socket = socket;this.isRuning = true;try {console = new BufferedReader(new InputStreamReader(System.in));dos = new DataOutputStream(socket.getOutputStream());} catch (IOException e) {System.out.println("======1=====");this.release();}}// 从控制台获取消息private String getStrFromConsole() {try {return console.readLine();} catch (IOException e) {e.printStackTrace();}return "";}// 发送消息public void send(String msg) {try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {e.printStackTrace();System.out.println("======3=====");this.release();}}// 释放资源private void release() {this.isRuning = false;IOUtils.close(dos, console, socket);}@Overridepublic void run() {while(isRuning) {String msg = getStrFromConsole();if (!msg.equals("")) {this.send(msg);}}}}

4、多线程封装接收端

package com.xzlf.chat;import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;/*** 使用多线程封装接收端* @author xzlf**/
public class Receive implements Runnable {private Socket socket;private DataInputStream dis;private boolean isRuning;public Receive(Socket socket) {this.socket = socket;this.isRuning = true;try {dis = new DataInputStream(socket.getInputStream());} catch (IOException e) {System.out.println("======2=====");this.release();}}// 接收消息public String receive() {String msg = "";try {msg = dis.readUTF();} catch (IOException e) {System.out.println(e);System.out.println("======4=====");release();}return msg;}// 释放资源private void release() {this.isRuning = false;IOUtils.close(dis, socket);}@Overridepublic void run() {while(isRuning) {String msg = receive();if(!msg.equals("")) {System.out.println(msg);}}}
}

5、客户端

package com.xzlf.chat;import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;/*** 聊天室:客户端* @author xzlf**/
public class TMultiClient {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("======client======");// 1、指定ip + 端口 建立连接Socket socket = new Socket("localhost", 8888);// 2、客户端收发消息new Thread(new Send(socket)).start();new Thread(new Receive(socket)).start();}
}

运行服务端和客户端:

先每个客户端只能自己跟自己聊。

实现群聊:

1、加入容器(使用JUC包下的并发容器CopyOnWriteArrayList),并添加给其他用户发送消息方法
添加容器:

public class Chat {private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<Channel>();public static void main(String[] args) throws IOException {System.out.println("======server======");// 1、指定端口创建服务端ServerSocket server = new ServerSocket(8888);while(true) {// 2、每进来一个客户端启动一个线程Socket socket = server.accept();Channel c = new Channel(socket);all.add(c);System.out.println("一个客户端建立了连接");new Thread(c).start();}}
添加群发方法
// 群聊:发送消息给其他人private void sendOthers(String msg, boolean isSys) {for(Channel other : all) {if(other == this) {continue;}if (!isSys) {// 群聊消息other.send(this.name + "说:" + msg);}else {// 系统消息other.send(msg);}}}

2、在初始化发送端,写入自己用户名并在初始化就发送
客户端启动时,输入用户名

public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("======client======");BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.print("请输入用户名:");String name = br.readLine();// 1、指定ip + 端口 建立连接Socket socket = new Socket("localhost", 8888);// 2、客户端收发消息new Thread(new Send(socket, name)).start();new Thread(new Receive(socket)).start();}
}
发送线程初始化时立马发送用户名:
public class Send implements Runnable{private Socket socket;private DataOutputStream dos;private BufferedReader console;private boolean isRuning;private String name;public Send(Socket socket, String name) {this.socket = socket;this.name = name;try {this.isRuning = true;console = new BufferedReader(new InputStreamReader(System.in));dos = new DataOutputStream(socket.getOutputStream());// 发送用户名this.send(name);} catch (IOException e) {System.out.println("======1=====");this.release();}}
服务端的channel类中初始化时立马接收用户名并保存

3、服务端(静态内部类Channel类中)在初始化时立即获取用户名并给用户发送欢迎信息同时给其他用户发提示信息(系统消息)

static class Channel implements Runnable{private Socket socket;private DataInputStream dis;private DataOutputStream dos;private boolean isRuning;private String name;public Channel(Socket socket) {this.socket = socket;this.isRuning = true;try {dis = new DataInputStream(socket.getInputStream());dos = new DataOutputStream(socket.getOutputStream());// 获取用户名this.name = receive();this.send("欢迎你的到来");this.sendOthers(this.name + "来了xxx聊天室", true);} catch (IOException e) {System.out.println("------1------");this.release();}}

4、用户关闭线程,给其他用户发送提示信息,提示用户已离开

// 释放资源private void release() {this.isRuning = false;IOUtils.close(dis, dos, socket);// 退出all.remove(this);sendOthers(this.name + "离开了聊天室。。。", true);}

运行测试:

实现私聊:

通过判断用户输入信息是否包含“@xxx:”确定是否为私聊,修改群发方法:

/*** 群聊:获取自己的信息,发送消息给其他人* 私聊:约定数据格式: @xxx:msg* @param msg* @param isSys*/private void sendOthers(String msg, boolean isSys) {if(msg.startsWith("@")) {// 私聊int endIndex = msg.indexOf(":");String targetName = msg.substring(1, endIndex);String info = msg.substring(endIndex + 1);for(Channel other : all) {if(other.name.equals(targetName)) {other.send(this.name + "悄悄对你说:" + info);}}}else {// 群聊for(Channel other : all) {if(other == this) {continue;}if (!isSys) {// 群聊消息other.send(this.name + "说:" + msg);}else {// 系统消息other.send(msg);}}}}

好了,现在已经实现了私聊。
运行测试一下:

Java 网络编程 -- 基于TCP 实现聊天室 群聊 私聊相关推荐

  1. Java WebSocket实现网络聊天室(群聊+私聊)

    WebChat聊天室 2018.02.26 源码地址早就贴了呀, 留邮箱不如自己下载 项目地址: https://github.com/Amayadream/WebChat 2017.01.11更新 ...

  2. Java网络编程:TCP实现聊天

    客户端 package com.zhl.nett;import java.io.IOException; import java.io.OutputStream; import java.net.In ...

  3. PHP+AJAX高性能聊天室(群聊+私聊)

    无需服务端 Anlin_chat 一个多功能免费开源的网页聊天室,基于php+mysql+js运行 无需服务端,高效+极快的运行速度 (超高安全性)支持分类帖子推送兼容QQ内置,微信内置,Firefo ...

  4. BIO聊天室(群聊+私聊)

    功能:群聊+私发+上线提醒+下线提醒+查询在线用户 文件 Utils FinalValue Message Server Client Receive Send Utils package morem ...

  5. Java网络编程:TCP实现群聊私聊代码

    Java网络编程:TCP实现群聊&私聊代码 和上一篇博客差不多,只不过是在群里的基础之上增加了私聊的功能,我们约定,私聊格式为:@xxx:msg 如何实现私聊呢,加入客户端c给服务器发送消息, ...

  6. 网络编程——基于TCP协议的通讯录【课程设计】

    网络编程--基于TCP协议的通讯录[课程设计] 本文目录 网络编程--基于TCP协议的通讯录[课程设计] 一.设计题目和要求 设计目标: 课程设计系统组成及模块功能: 二.设计内容 服务端 客户端 S ...

  7. SpringBoot + Vue 实现基于 WebSocket 的聊天室(单聊)

    前言 在前一篇文章SpringBoot 集成 STOMP 实现一对一聊天的两种方法中简单介绍了如何利用 STOMP 实现单聊,本文则将以一个比较完整的示例展示实际应用,不过本文并未使用 STOMP,而 ...

  8. Java网络编程——基于UDP协议的聊天室

    UDP简述    UDP(User Datagram Protocol)协议是Internet 协议集支持的一个无连接的传输协议,中文名为用户数据报协议.它为应用程序提供了一种无需建立连接就可以发送封 ...

  9. 06 java GUI 网络编程:图形界面聊天室

    仿照第4篇笔记的形式,笔者决定将GUI和网络编程部分用综合练习的方式来总结.练习项目是有图形界面的聊天室,用到了GUI中的javax.swing包和网络编程中的TCP/socket编程.GUI部分的难 ...

  10. Linux网络编程——基于tcp/ip的模拟聊天(文件传输)工具

    开发平台:Linux 开发工具:Ubuntu, sourceInsight4.0 项目介绍: 本项目基于TCP/IP协议创建一个网络通信系统,可以实现客户之间的聊天通信以及文件传输,同时利用进程实现多 ...

最新文章

  1. 青少年电子信息智能创新大赛 赛项说明(Python编程创新挑战赛)
  2. 怎样使用Debussy+ModelSim快速查看前仿真波形
  3. Google Play应用上架流程(含踩坑经验)
  4. SAP和CRM相关的标准教材,学通了这些,就算是CRM专家了
  5. html导入夸克,index.html
  6. linux系统怎么安装python3视频教程_Linux系统,python3.7安装教程
  7. 在应用程序中操作NorFlash
  8. Ajax案例之聊天机器人
  9. 广东第一高中生_广东高中排行榜TOP10,有你的母校吗?
  10. linux 硬盘报错日志,Linux内核I/O系统报错日志与硬盘故障对应关系
  11. Unity高级知识点总结:性能优化与图形渲染进阶!
  12. android之ION内存管理器(1)-- 简介
  13. ActiveMQ——如何监控ActiveMQ
  14. DialogBox函数参数
  15. 手机发不出短信 htc hero g3
  16. 《Python黑帽子》python3代码实现(第六章)
  17. 游戏名称:猜人名游戏
  18. 灰度图像的锐化——拉普拉斯算子
  19. JavaSE-02(类与对象、枚举、接口)
  20. 手机上有什么给短视频配音的软件

热门文章

  1. java 二次封装azkaban 实现azkaban任务的执行
  2. html css二级下拉菜单,下拉导航 - 两级菜单(CSS/HTML)
  3. python打印文档添加条码_使用Python在Excel中批量生成条形码
  4. Windows 8.1 安装Ruby on Rails手记
  5. 一个乞丐的故事(强烈推荐)
  6. 2019/3/20统计单词数
  7. 需要u3d资源吗,免费送哦
  8. win10 将中文名修改成英文名
  9. 方正中间件创业大赛南京赛区圆满落幕
  10. android 应用市场图尺寸,【干货】最新App应用市场截图尺寸大全