版本1:群聊功能

使用TCP

运行方式:先开服务端,再开任意个数客户端。在控制台可以实现群聊功能。

效果

代码
服务端

package cn.hanquan.groupchat;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;/** 在线聊天室:服务端* 服务器不生产内容,只是转发*/
public class Chat {public static CopyOnWriteArrayList<Channel> allChannel = new CopyOnWriteArrayList<>();public static void main(String[] args) throws IOException {System.out.println("-----Server-----");ServerSocket server = new ServerSocket(8888);// 指定端口 创建服务器while (true) {Socket client = server.accept();// 阻塞式等待链接System.out.println("A client succesfully connected.");new Thread(new Channel(client)).start();// 新线程}}static class Channel implements Runnable {private Socket client;private DataOutputStream dos;private DataInputStream dis;boolean isRunning = true;public Channel(Socket client) {allChannel.add(this);this.client = client;try {this.dos = new DataOutputStream(client.getOutputStream());this.dis = new DataInputStream(client.getInputStream());} catch (IOException e) {System.out.println("构造器异常" + e);}}// 接收消息public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {isRunning = false;release();}return msg;}// 发送消息给当前Channelpublic void send(String msg) {if (msg == null)return;try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {isRunning = false;release();}}// 发送消息给所有Chanelpublic void sendAll(String msg) {for (Channel channel : allChannel) {if (channel == this)// 不发给自己continue;channel.send(msg);}}// 释放资源public void release() {new Utils().close(dis, dos, client);}@Overridepublic void run() {while (isRunning) {String msg = receive();sendAll(msg);}}}
}

客户端

package cn.hanquan.groupchat;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;/** 在线聊天室:客户端*/
public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");Socket client = new Socket("localhost", 8888);// 建立链接new Thread(new Send(client)).start();new Thread(new Receive(client)).start();}// 发送public static class Send implements Runnable {String name;Socket client;DataOutputStream dos;BufferedReader console;DataInputStream dis;boolean isRunning = true;public Send(Socket client) {this.name = inputName();this.client = client;try {dos = new DataOutputStream(client.getOutputStream());console = new BufferedReader(new InputStreamReader(System.in));dis = new DataInputStream(client.getInputStream());} catch (Exception e) {System.out.println("构造器异常" + e);}}@Overridepublic void run() {while (isRunning) {String str = null;try {str = console.readLine();} catch (IOException e) {e.printStackTrace();}send(str);}}public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();}return msg;}public void send(String msg) {try {dos.writeUTF(this.name + ": " + msg);dos.flush();} catch (IOException e) {e.printStackTrace();}}public void release() {new Utils().close(dis, dos, client);}public String inputName() {System.out.println("请输入用户名:");BufferedReader sc = new BufferedReader(new InputStreamReader(System.in));String name = null;try {name = sc.readLine();} catch (IOException e) {e.printStackTrace();}System.out.println("欢迎: " + name+" 进入聊天室~ 你现在可以畅所欲言~");// c.close();return name;}}// 接收public static class Receive implements Runnable {Socket client;DataOutputStream dos;BufferedReader console;DataInputStream dis;boolean isRunning = true;public Receive(Socket client) {this.client = client;try {dos = new DataOutputStream(client.getOutputStream());console = new BufferedReader(new InputStreamReader(System.in));dis = new DataInputStream(client.getInputStream());} catch (Exception e) {System.out.println("构造器异常" + e);}}@Overridepublic void run() {while (isRunning) {String msg = receive();System.out.println(msg);}}public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();}return msg;}public void release() {new Utils().close(dis, dos, client);}}
}

工具类

package cn.hanquan.groupchat;import java.io.Closeable;public class Utils {public void close(Closeable... targets) {for (Closeable t : targets) {try {if (null != t) {t.close();}} catch (Exception e) {e.printStackTrace();}}}
}

版本2: 进入提醒功能

示例

-----Client-----
请输入用户名:
布小谷
布小谷, Welcome ~
(系统消息) [魔鬼] 进入了聊天室
(系统消息) [逆风微笑的程序猿] 进入了聊天室
魔鬼: 我要出去了
再见哦
逆风微笑的程序猿: 再见啊

服务端

package cn.hanquan.groupchat;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;/** 在线聊天室:服务端* 服务器不生产内容,只是转发* * 改进:* 增加系统消息功能,新人登录之后系统消息提示(群发时候加个bool即可)* 用户关闭后,从容器中删除allChannel.remove(this);并且系统发出广播退出通知*/
public class Chat {public static CopyOnWriteArrayList<Channel> allChannel = new CopyOnWriteArrayList<>();public static void main(String[] args) throws IOException {System.out.println("-----Server-----");ServerSocket server = new ServerSocket(8888);// 指定端口 创建服务器while (true) {Socket client = server.accept();// 阻塞式等待链接System.out.println("A client succesfully connected.");new Thread(new Channel(client)).start();// 新线程}}// 一个Channel线程就是一个Client连接static class Channel implements Runnable {private Socket client;private DataOutputStream dos;private DataInputStream dis;public String clientName;boolean isRunning = true;public Channel(Socket client) {allChannel.add(this);this.client = client;try {this.dos = new DataOutputStream(client.getOutputStream());this.dis = new DataInputStream(client.getInputStream());} catch (IOException e) {System.out.println("构造器异常" + e);}}// 接收消息public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {isRunning = false;release();}if (msg != null) {if (msg.indexOf("(系统消息)") == 0) {this.clientName = msg.substring(msg.indexOf("[") + 1, msg.indexOf("]"));}}return msg;}// 发送消息给当前Channelpublic void send(String msg) {if (msg == null)return;try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {isRunning = false;release();allChannel.remove(this);}}// 发送消息给所有Channelpublic void sendAll(String msg) {for (Channel channel : allChannel) {if (channel == this)// 不发给自己continue;channel.send(msg);}}// 释放资源public void release() {new Utils().close(dis, dos, client);}@Overridepublic void run() {while (isRunning) {String msg = receive();sendAll(msg);}}}
}

客户端

package cn.hanquan.groupchat;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;/** 在线聊天室:客户端*/
public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");Socket client = new Socket("localhost", 8888);// 建立链接new Thread(new Send(client)).start();new Thread(new Receive(client)).start();}// 发送public static class Send implements Runnable {String uname;Socket client;DataOutputStream dos;BufferedReader console;DataInputStream dis;boolean isRunning = true;// 构造器public Send(Socket client) {this.uname = inputName();this.client = client;try {dos = new DataOutputStream(client.getOutputStream());console = new BufferedReader(new InputStreamReader(System.in));dis = new DataInputStream(client.getInputStream());} catch (Exception e) {System.out.println("构造器异常" + e);}send("进入了聊天室", true);}@Overridepublic void run() {while (isRunning) {String str = null;try {str = console.readLine();} catch (IOException e) {e.printStackTrace();}send(str, false);}}// 接收public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();}return msg;}// 发送public void send(String msg, boolean system) {try {if (system)dos.writeUTF("(系统消息) [" + this.uname + "] " + msg);elsedos.writeUTF(this.uname + ": " + msg);dos.flush();} catch (IOException e) {e.printStackTrace();}}// 释放public void release() {new Utils().close(dis, dos, client);}public String inputName() {System.out.println("请输入用户名:");BufferedReader sc = new BufferedReader(new InputStreamReader(System.in));String name = null;try {name = sc.readLine();} catch (IOException e) {e.printStackTrace();}System.out.println(name + ", Welcome ~ ");return name;}}// 接收public static class Receive implements Runnable {Socket client;DataOutputStream dos;BufferedReader console;DataInputStream dis;boolean isRunning = true;public Receive(Socket client) {this.client = client;try {dos = new DataOutputStream(client.getOutputStream());console = new BufferedReader(new InputStreamReader(System.in));dis = new DataInputStream(client.getInputStream());} catch (Exception e) {System.out.println("构造器异常" + e);}}@Overridepublic void run() {while (isRunning) {String msg = receive();System.out.println(msg);}}public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();}return msg;}public void release() {new Utils().close(dis, dos, client);}}
}

工具类

版本2的工具类和版本1的工具类相同,没有改动

package cn.hanquan.groupchat;import java.io.Closeable;public class Utils {public void close(Closeable... targets) {for (Closeable t : targets) {try {if (null != t) {t.close();}} catch (Exception e) {e.printStackTrace();}}}
}

运行效果

先运行一个Chat.java

再运行一个Client.java(name:魔鬼)
再运行一个Client.java(name:布小谷)
再运行一个Client.java(name:逆风微笑的程序猿)

再退出一个Client.java(name:魔鬼)

…此版本后来有改动。因为一个线程退出后,其数据不再有效,因此无法使用其类内部的sendall方法。所以取消退出提醒功能。如果想要全局提醒,可以考虑加入一个独立的紫铜消息线程

版本3: 群聊/私聊

此版本增加了私聊功能~

规定的私聊语法:

@某人 你要说的话

是最终版了,但是里面有一些用户可能输入非法字符串的bug,比如输入@@就直接string outofbound崩了,这些bug的修复,还需要进一步过滤字符串,在这里就先不改了。

服务端

package cn.hanquan.groupchat;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;/** 在线聊天室:服务端* 服务器不生产内容,只是转发* * 改进:* 增加系统消息功能,新人登录之后系统消息提示(群发时候加个bool即可)* 用户关闭后,从容器中删除allChannel.remove(this);并且系统发出广播退出通知*/
public class Chat {public static CopyOnWriteArrayList<Channel> allChannel = new CopyOnWriteArrayList<>();public static void main(String[] args) throws IOException {System.out.println("-----Server-----");ServerSocket server = new ServerSocket(8888);// 指定端口 创建服务器while (true) {Socket client = server.accept();// 阻塞式等待链接System.out.println("A client succesfully connected.");new Thread(new Channel(client)).start();// 新线程}}// 一个Channel线程就是一个Client连接static class Channel implements Runnable {private Socket client;private DataOutputStream dos;private DataInputStream dis;public String clientName;boolean isRunning = true;public Channel(Socket client) {allChannel.add(this);this.client = client;try {this.dos = new DataOutputStream(client.getOutputStream());this.dis = new DataInputStream(client.getInputStream());} catch (IOException e) {System.out.println("构造器异常" + e);}}// 接收消息public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {isRunning = false;release();}if (msg != null) {if (msg.indexOf("(系统消息)") == 0) {this.clientName = msg.substring(msg.indexOf("[") + 1, msg.indexOf("]"));}}return msg;}// 发送消息给当前Channelpublic void send(String msg) {if (msg == null)return;try {dos.writeUTF(msg);dos.flush();} catch (IOException e) {isRunning = false;release();allChannel.remove(this);}}// 发送消息给所有Channelpublic void sendAll(String msg) {try {if (msg.indexOf("@") != -1) {// 私聊格式 @SomeOne say...String toName = msg.substring(msg.indexOf("@") + 1, msg.indexOf(" ", msg.indexOf("@") + 1));for (Channel channel : allChannel) {if (channel.clientName.equals(toName)) { // 发给自己指定人channel.send(msg);break;}}} else {// 群发for (Channel channel : allChannel) {if (channel == this)// 不发给自己continue;channel.send(msg);}}} catch (NullPointerException e) {System.out.println("One client exit");isRunning = false;release();allChannel.remove(this);}}// 释放资源public void release() {new Utils().close(dis, dos, client);}@Overridepublic void run() {while (isRunning) {String msg = receive();sendAll(msg);}}}
}

客户端

package cn.hanquan.groupchat;import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;/** 在线聊天室:客户端*/
public class Client {public static void main(String[] args) throws UnknownHostException, IOException {System.out.println("-----Client-----");Socket client = new Socket("localhost", 8888);// 建立链接new Thread(new Send(client)).start();new Thread(new Receive(client)).start();}// 发送public static class Send implements Runnable {String uname;Socket client;DataOutputStream dos;BufferedReader console;DataInputStream dis;boolean isRunning = true;// 构造器public Send(Socket client) {this.uname = inputName();this.client = client;try {dos = new DataOutputStream(client.getOutputStream());console = new BufferedReader(new InputStreamReader(System.in));dis = new DataInputStream(client.getInputStream());} catch (Exception e) {System.out.println("构造器异常" + e);}send("进入了聊天室", true);}@Overridepublic void run() {while (isRunning) {String str = null;try {str = console.readLine();} catch (IOException e) {e.printStackTrace();}send(str, false);}}// 接收public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();}return msg;}// 发送public void send(String msg, boolean system) {try {if (system)dos.writeUTF("(系统消息) [" + this.uname + "] " + msg);elsedos.writeUTF(this.uname + ": " + msg);dos.flush();} catch (IOException e) {e.printStackTrace();}}// 释放public void release() {new Utils().close(dis, dos, client);}public String inputName() {System.out.println("请输入用户名:");BufferedReader sc = new BufferedReader(new InputStreamReader(System.in));String name = null;try {name = sc.readLine();} catch (IOException e) {e.printStackTrace();}System.out.println(name + ", Welcome ~ ");return name;}}// 接收public static class Receive implements Runnable {Socket client;DataOutputStream dos;BufferedReader console;DataInputStream dis;boolean isRunning = true;public Receive(Socket client) {this.client = client;try {dos = new DataOutputStream(client.getOutputStream());console = new BufferedReader(new InputStreamReader(System.in));dis = new DataInputStream(client.getInputStream());} catch (Exception e) {System.out.println("构造器异常" + e);}}@Overridepublic void run() {while (isRunning) {String msg = receive();System.out.println(msg);}}public String receive() {String msg = null;try {msg = dis.readUTF();} catch (IOException e) {e.printStackTrace();}return msg;}public void release() {new Utils().close(dis, dos, client);}}
}

工具类

package cn.hanquan.groupchat;import java.io.Closeable;public class Utils {public void close(Closeable... targets) {for (Closeable t : targets) {try {if (null != t) {t.close();}} catch (Exception e) {e.printStackTrace();}}}
}

运行效果

【Java网络编程(四)】手写TCP聊天室——控制台版相关推荐

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

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

  2. Java网络编程学习——简单模拟在线聊天

    Java网络编程学习--简单模拟在线聊天 学了java网络,也是该做个小案例来巩固一下了. 本次案例将使用UDP和多线程模拟即时聊天,简单练练手. 1.前提知识 需要知道简单的IO流操作,以及简单的U ...

  3. Java——网络编程(UDP与TCP通信及实现聊天案例)

    目录 1.什么是网络通信协议? 2.TCP/IP协议 3.协议分类 3.1.UDP协议 3.2.TCP协议 4.网络编程三大要素 4.1.协议 4.2.IP地址 4.3.端口号 5.InetAddre ...

  4. -1-7 java 网络编程基本知识点 计算机网络 TCP/IP协议栈 通信必备 tcp udp

    计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来, 在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统. 网络编程 ...

  5. 【网络编程】之七、select聊天室

    好久没有用MFC 来写代码了,手都生疏了,悲剧啊,好多API 都去查的  哎~~~ 好了 下面把 我们聊天室的代码贴出: select函数封装: [cpp] view plaincopy BOOL C ...

  6. java 网络编程(二) tcp传输实现客户端和服务端进行信息交流

    1.使用Tcp从一台电脑往另一台电脑上发送文本数据 客户端: import java.io.*; import java.net.*; /**** 客户端,* 通过查阅socket对象,发现在该对象建 ...

  7. java网络编程案例9-1模拟微信聊天

    题目:如今微信已经成为人们 生活中必不可少的一款社交软件.本案例要求编写一个程序模拟微信聊天功能,在实现本案例时,要求使用多线程与UDP通信完成消息的发送和接收 代码如下: SendTask类: pa ...

  8. 【Socket网络编程进阶与实战】-----聊天室升级版实战

    前言 分享:并发客户端性能优化,数据三层缓冲区优化,心跳包必要性与策略选择等 一.消息调度分析 package com.zcw

  9. 【计算机网络】网络协议与计算机网络体系结构(OSI参考模型、TCP/IP体系、网络通信标准化组织)及 Java网络编程

    网络协议与计算机网络体系结构 知识点总结 网络协议与分层体系结构 开放系统互连参考模型OSI/RM 五层的体系结构 [例]主机甲向主机乙发送数据 实体和服务访问点SAP PDU:协议数据单元 TCP/ ...

最新文章

  1. JQuery EasyUI的常用组件
  2. python3字符串属性(二)
  3. Java笔记-使用Kaptcha验证码框架
  4. 信息学奥赛C++语言:最高分数的学生姓名
  5. Spark 性能优化指南(官网文档)
  6. group() 数组java_java 根据每个分组个数,分解数组. | 学步园
  7. ELK下filebeat性能调优
  8. 28个极简代码——python
  9. vue 登录页背景-粒子特效(Vue-Particles)
  10. Java程序员的第一个Python小程序:京东畅销书榜爬虫
  11. chm混淆+qq白利用免杀360主动防御
  12. 打字机效果的实现与应用
  13. CSICTF2020随缘Writeup
  14. Netlogo入门(一)
  15. Altium Designer 17及以上版本快速画出Keep-Out layer层以便于覆铜操作
  16. 3个APP海外推广方式,不走寻常路
  17. 测试电脑的软件3dm,有用的小工具检测你的电脑能否运行Oculus Rift
  18. 网页文字无法复制粘贴到word中怎么办
  19. mysql errorcode 1366_mysql插入emoji表情报 error code [1366]
  20. 强强联手 东钱湖变身高端度假区

热门文章

  1. 中石油训练赛 - 小说(最短路+二分)
  2. uva12099 Bookcase ACM NWERC
  3. Keras-常用代码
  4. 安卓入门系列-04常见布局之LinearLayout(线性布局)
  5. 【数据结构】图的遍历(BFS和DFS)
  6. go get国内解决办法汇总
  7. cocos2d-x初探学习笔记(1)--HelloWorld
  8. 线程池原理及创建(C++实现)
  9. C++ 面向对象(二)多态 : 虚函数、多态原理、抽象类、虚函数表、继承与虚函数表
  10. docker学习笔记(四)docker数据持久化volume