前言

闲言少叙,上代码!

代码编写

server服务端

/*** 服务端*/

public classServer {private static ServerSocket server = null;private static Socket ss = null;/*** 客户端集合*/

private static Map serverThreadMap = new HashMap();public static voidmain(String[] args) {

server();

}/*** 普通服务器连接*/

private static voidserver() {try{//建立服务端

server = new ServerSocket(10010);

System.out.println("server端已启动!");while (true) {//创建接收接口

ss =server.accept();//启动新客户监听线程

newServerThread(server, ss).start();

}

}catch(IOException e) {

e.printStackTrace();

}finally{try{

ss.close();

server.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}/*** 内部类线程,每连接一个新的客户端就启动一个对应的监听线程*/@SuppressWarnings("Duplicates")private static class ServerThread extendsThread {

ServerSocket server= null;

Socket socket= null;

InputStream is= null;

OutputStream os= null;

String clientName= null;boolean alive = true;publicServerThread() {

}

ServerThread(ServerSocket server, Socket socket) {this.socket =socket;this.server =server;

}

@Overridepublic voidrun() {//接收数据

try{

is=socket.getInputStream();//发送

os =socket.getOutputStream();//缓存区

byte[] b = new byte[1024];int length = 0;while(alive) {//接收从客户端发送的消息

length =is.read(b);if (length != -1) {//文本消息

String message = new String(b, 0, length);//JSON字符串转 HashMap

HashMap hashMap = new ObjectMapper().readValue(message, HashMap.class);//消息类型

String type = (String) hashMap.get("type");//新连接

if ("OPEN".equals(type)) {

clientName= (String) hashMap.get("clientName");//添加客户端到集合容器中

serverThreadMap.put(clientName, this);

System.out.println(clientName+ "连接成功!");

System.out.println("当前客户端数量:" +serverThreadMap.size());

}//关闭

if ("CLOSE".equals(type)) {

alive= false;

System.err.println(clientName+ "退出连接,关闭监听线程!");

}//文本消息

if ("MESSAGE".equals(type)) {

String msg= (String) hashMap.get("message");

String chat= (String) hashMap.get("chat");//群聊(广播)

if ("GROUP".equals(chat)) {//遍历容器,给容器中的每个对象转发消息

for(ServerThread st : serverThreadMap.values()) {//向其他客户端发送数据

if (st != this) {

st.os.write(new String(b, 0, length).getBytes());

}

}//后台打印

System.out.println(clientName + "向所有人说:" +msg);

}//私聊

if ("PRIVATE".equals(chat)) {

String to= (String) hashMap.get("to");

serverThreadMap.get(to).os.write(new String(b, 0, length).getBytes());//后台打印

System.out.println(clientName + "向" + to + "说:" +msg);

}

}

}

}

}catch(IOException e) {

e.printStackTrace();

System.err.println("与" + clientName + "连接中断,被迫关闭监听线程!");

}finally{try{

serverThreadMap.remove(clientName);

System.out.println("当前客户端数量:" +serverThreadMap.size());

os.close();

is.close();

socket.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}

}

}

client客户端

/*** 客户端*/@SuppressWarnings("Duplicates")public classClient {private static String serverInetAddress = "127.0.0.1";private static int serverPort = 10010;private static Socket client = null;private static OutputStream os = null;private static InputStream is = null;private staticString thisName;private static boolean alive = true;/*** 客户端连接服务器*/@SuppressWarnings("unused")public static voidopen(String name) {try{

thisName=name;

InetAddress inetAddress=InetAddress.getLocalHost();//建立连接

client = newSocket(serverInetAddress, serverPort);//数据流发送数据

os =client.getOutputStream();

sendMsg("{\"type\":\"OPEN\",\"clientName\":\"" + name + "\"}");//数据流接收数据

is =client.getInputStream();byte[] b = new byte[1024];int length = 0;while(alive) {//接收从服务器发送回来的消息

length =is.read(b);if (length != -1) {

onMsg(new String(b, 0, length));

}

}

}catch(IOException e) {

e.printStackTrace();

}finally{try{//关流

os.close();

client.close();

is.close();

}catch(IOException e) {

e.printStackTrace();

}

}

}/*** 关闭客户端*/

public static voidclose() {

sendMsg("{\"type\":\"CLOSE\"}");

alive= false;

}/*** 发送消息*/

public static voidsendMsg(String msg) {try{//调用发送

os.write(msg.getBytes());

}catch(IOException e) {

e.printStackTrace();

}

}/*** 收到消息的回调*/

private static voidonMsg(String message) {//JSON字符串转 HashMap

HashMap hashMap = null;try{

hashMap= new ObjectMapper().readValue(message, HashMap.class);

}catch(IOException e) {

e.printStackTrace();

}

String msg= (String) hashMap.get("message");

String chat= (String) hashMap.get("chat");

String from= (String) hashMap.get("from");

String to= (String) hashMap.get("to");//群聊

if ("GROUP".equals(chat)) {//后台打印

System.out.println(thisName + "收到(" + to + ")群聊消息:" +msg);

}//私聊

if ("PRIVATE".equals(chat)) {//后台打印

System.out.println(thisName + "收到(" + from + ")私聊消息:" +msg);

}

}/*** 获取thisName*/

public staticString getThisName() {returnthisName;

}

}

controller模拟调用客户端

@RequestMapping("/sendMsg/{chat}/{msg}")public void sendMsg(@PathVariable("chat") String chat, @PathVariable("msg") String msg) {if ("group".equals(chat.toLowerCase())) {//群聊

Client.sendMsg("{\"type\":\"MESSAGE\",\"chat\":\"GROUP\",\"from\":\""+Client.getThisName()+"\",\"to\":\"群号:xxxx\",\"message\":\"" + msg + "\"}");

}else{//私聊

Client.sendMsg("{\"type\":\"MESSAGE\",\"chat\":\"PRIVATE\",\"from\":\""+Client.getThisName()+"\",\"to\":\"" + chat + "\",\"message\":\"" + msg + "\"}");

}

}

@RequestMapping("/starClient/{name}")public void starClient(@PathVariable("name") String name) {

Client.open(name);

}

@RequestMapping("/closeClient")public voidcloseClient() {

Client.close();

}

效果展示

一个服务端、两个客户端(两个不同的工程、模拟两个客户端),注意,要先启动服务端,再启动客户端!

使用controller模拟启动两个客户端:

http://localhost:10086/springboot/user/starClient/张三

http://localhost:10087/starClient/李四

张三发送群聊

http://localhost:10086/springboot/user/sendMsg/group/大家好啊

张三是发送者,server不再转发此消息给张三

张三向李四发送私聊信息

http://localhost:10086/springboot/user/sendMsg/李四/老表,你好啊

张三是发送者,server不再转发此消息给张三

李四回复张三私聊信息

李四是发送者,server不再转发此消息给李四

下线、掉线

张三:http://localhost:10086/springboot/user/closeClient

李四:直接终止客户端进程

后记

这个例子服务端每次有新的客户端连接进来,就启动一个线程去监听与此客户端的通信,当有大量客户端时就不适用了,而且涉及界面时,java socket不能主动给浏览器发送消息,界面聊天只能用轮询的方式实现,不好;多客户端、涉及有界面的聊天建议使用websocket(猛戳这里 -->WebSocket+Java 私聊、群聊实例)。

java群聊_Java Socket通信实现私聊、群聊相关推荐

  1. java socket群聊_java socket来实现私聊和群聊-简易版

    public class MyServer { List list=new ArrayList(); public static void main(String[] args) { try { // ...

  2. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    JAVA 中原生的 socket 通信机制 转载自:https://github.com/jasonGeng88/blog 当前环境 jdk == 1.8 知识点 socket 的连接处理 IO 输入 ...

  3. connect: 网络不可达_Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    本文转自:https://github.com/jasonGeng88/blog 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https ...

  4. java socket编程聊天室_Java Socket通信之聊天室功能

    Java Socket通信之聊天室功能 发布时间:2020-10-17 14:36:00 来源:脚本之家 阅读:73 作者:LY_624 本文实例为大家分享了Java Socket聊天室功能的具体代码 ...

  5. java socket 端口_Java Socket通信如何摆平自身端口问题

    Java Socket通信在使用的时候有不少的问题,在端口编程上来说是一个十分重要的.下面我们就看看Java Socket通信如何才能更好的使用相关的代码.希望大家有所帮助. 事实上网络编程简单的理解 ...

  6. [其他]JAVA与C#的Socket通信

    在日常的开发中,不同的传感器支持的开发语言常常是不同的.例如Kinect一般是用C++开发的,Leapmotion用JAVA开发比较多. 去年暑假(17年暑假)做的一个项目是:用Leapmotion捕 ...

  7. Java 网络通信必备之socket通信基本原理介绍

    Java socket通信基本原理介绍 Java socket通信在不断的进行相关代码的开发,下面我们就看看如何才能更好的使用有关技术为我们的编程工作带来一定的帮助. 作者:佚名来源:互联网|2010 ...

  8. Android java和C的Socket通信demo(可用)

    原址 关于Android应用与Framework的socket通信,相信关心这个问题的朋友们已经看过<android使用socket使底层和framework通信>这篇文章,美中不足的是作 ...

  9. java共享内存_Java进程通信之映像文件共享内存

    Java进程通信之映像文件共享内存 1. 共享内存 vs 进程通信 对UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种.但windows实际上只有影像文件共享内存一种. 而说到进程通信 ...

最新文章

  1. mapx实现热点效果
  2. ASP.NET常被忽视的一些细节
  3. iPhone socket 编程之BSD Socket篇
  4. leader选举的源码分析
  5. 【期望DP】概率充电器(luogu 4284)
  6. React 学习笔记 —— Ref Hook
  7. flutter打包的app有多大_前端大势所趋---Flutter 这篇文章会让你行动起来
  8. Hibernate一对一映射示例注释
  9. 对windows更多的理解
  10. 关于url传参中文乱码问题
  11. windows下springboot项目部署elk日志系统教程elasticsearch与logstash与kibana
  12. Google Chrome 工程师:JavaScript 不容错过的八大优化建议
  13. mysql日志课程_【mysql课程七】 MySQL日志管理
  14. 计算机的照相机功能,让我来告诉你单反相机那10项不可思议的功能!
  15. win10无线网卡黄色感叹号
  16. Unity 文字转语音
  17. mysql like查询很慢_MySQL Like模糊查询速度慢的解决方法
  18. 面试mysql之SQL优化总结一:索引的使用
  19. PowerJob 的自实现高可用方案,妙妙妙!
  20. Ai计算机类,【分享】计算机类SCI杂志--人工智能(无重复) - 信息科学 - 小木虫 - 学术 科研 互动社区...

热门文章

  1. 【论文笔记】Efficient and Realtime Distracted Driver Detection With MobileVGG Network
  2. IntelliJ IDEA编译项目报错 xxx包不存在 或 找不到符号
  3. 执业药师考试难度大吗丨备考攻略
  4. python高级编程---数据结构
  5. 在网页中加QQ链接,直接点击即可进行会话,一键加群链接
  6. 圣人不仁以百姓為芻狗 (感謝laolaoliu2002)
  7. 反序列化(Unserialize)漏洞详解
  8. latex beamer 空一行_全新透明设计联想拯救者电竞手机Pro至尊透明版 钛空无垠图赏...
  9. InstructPix2Pix: 动动嘴皮子,超越PS
  10. 【FXCG】调查显示美国通胀率将持续超过目标