当前位置: 首页 > news >正文

Java Socket Server TCP服务端向指定客户端发送消息

实现思路
首先需要知道java里如何创建一个Socket服务器端。

    //创建一个服务器端对象ServerSocket server = new ServerSocket(); //绑定启动的ip和端口号server.bind(new InetSocketAddress("127.0.0.1",8082));//启动成功后,调用accept()方法阻塞,//当有客户端成功连接时会生成一个Socket对象用于通讯Socket socket = server.accept();


提示:注意server.accept()方法调用会阻塞,只有新的客户端连接后才返回一个新的socket对象。如果一直未连接那么会一直处于阻塞状态

1、了解了如何创建一个socket服务器端后。那么如何实现给指定的连接客户端发送消息呢?首先我们可以知道只有有客户端连接服务器就会生成一个socket对象,socket对象中获取对应的输入输出流读取和写入就可以实现发送消息;也就是只要咱们把每次连接的socket保存起来,发送和接收数据就直接获取对应的socket就可以实现。
2、总结一下。也就是需要循环调用 server.accept()阻塞方法,对每个连接的socket保存起来。并对每一个socket实现读取写入操作。为了可用性。对于服务器阻塞方法需要单独创建一个线程进行阻塞等待连接操作。并且对于每一个连接的客户端单独创建一个线程进行读写操作。
好了话不多说直接上代码

项目源码
服务器端接口ISocketServer

/*** @description: 启用socket服务* @author * @date 2024/2/19 13:51* @version 1.0*/
public interface ISocketServer {/*** @description: 启动服务* @author liangxuelong* @date 2023/6/19 13:53* @version 1.0*/public void startServer();/*** @description: 停止服务* @author liangxuelong* @date 2023/6/19 13:53* @version 1.0*/public void stopServer();/*** @description: 判断是否启动* @author liangxuelong* @date 2023/6/19 14:01* @version 1.0*/public boolean isStart();}


服务器端实现一个抽象类AbstractSocketServer,定义启动、停止。查看连接状态等方法

/*** @author ** @version 1.0* @description:* @date 2023/6/19 14:04*/
public abstract class AbstractSocketServer implements ISocketServer{//服务器端口protected int port;//默认ip地址protected String ipAddress = "127.0.0.1";//默认最大连接数protected int maxConnectSize = 1;//当前连接状态protected boolean isConn = false;//java ServerSocket 对象private ServerSocket server;//保存所有连接通讯类protected ConcurrentHashMap<String,ICommunication> communications = new ConcurrentHashMap<>();public AbstractSocketServer(String ipAddress, int port) {this.ipAddress = ipAddress;this.port = port;}public AbstractSocketServer(int port) {this.port = port;}/*** @description: 启动服务* @author liangxuelong* @date 2023/6/19 16:14* @version 1.0*/@Overridepublic void startServer() {new Thread(() -> {try {if (isConn) {stopServer();}server = new ServerSocket();//绑定数据连接地址端口号server.bind(new InetSocketAddress(ipAddress,port));//绑定成功设置当前服务器状态为trueisConn = true;//循环等待客户端连接while(true){//阻塞 等待socket client 连接Socket socket = server.accept();//生成连接通讯对象SocketCommunication socketCommunication = new SocketCommunication(socket,this);new Thread(() -> {try {addCommunication(socketCommunication);socketCommunication.handle();} catch (Exception e) {e.printStackTrace();}removeCommunication(socket.getInetAddress().getHostAddress());}).start();}} catch (IOException ioException) {ioException.printStackTrace();}}).start();}/*** @description: 停止服务* @author liangxuelong* @date 2023/6/19 16:14* @version 1.0*/@Overridepublic void stopServer(){if (server != null) {try {server.close();} catch (IOException ioException) {ioException.printStackTrace();}isConn = false;removeAllCommunication();}}/*** @description: 给所有连接发送* @author liangxuelong* @date 2023/6/19 16:51* @version 1.0*/public void sendToALl(byte[] bytes){for (String ipAddress : communications.keySet()) {send(ipAddress,bytes);}}/*** @description: 给某个ip发送* @author liangxuelong* @date 2023/6/19 16:53* @version 1.0*/public boolean send(String ip,byte[] bytes) {if (communications.get(ip) == null)return false;try {communications.get(ip).send(bytes);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** @description: 当前是否启动 socket 服务端* @author liangxuelong* @date 2023/6/19 16:14* @version 1.0*/@Overridepublic boolean isStart() {return isConn;}/*** @description: 设置最大连接数量* @author * @date 2023/6/19 16:19* @version 1.0*/public void setMaxConnectSize(int maxConnectSize) {this.maxConnectSize = maxConnectSize;}/*** @description: 获取当前连接数据* @param:* @return: void* @author liangxuelong* @date: 2023/6/19*/public int getConnectSize(){return communications.size();}/*** @description: 获取当前所有连接的Ip地址* @param:* @return: void* @author liangxuelong* @date: 2023/6/19*/public Set<String> getConnectIpAddress(){return communications.keySet();}/*** @description: 添加连接对象* @author liangxuelong* @date 2023/6/19 15:14* @version 1.0*/protected void addCommunication(ICommunication communication) throws Exception {Socket socket = communication.getSocket();//判断是否超出最大连接数量,超出后断开连接if (maxConnectSize > communications.size()) {ICommunication iCommunication = communications.get(socket.getInetAddress().getHostAddress());if (iCommunication != null) {try {iCommunication.disconnect();} catch (Exception e) {e.printStackTrace();}communications.remove(socket.getInetAddress().getHostAddress());}communications.put(socket.getInetAddress().getHostAddress(),communication);} else {socket.close();throw new ConnectException(maxConnectSize);}}/*** @description: 移除连接对象* @author liangxuelong* @date 2023/6/19 15:14* @version 1.0*/public void removeCommunication(String ip){ICommunication iCommunication = communications.get(ip);if (iCommunication != null) {try {iCommunication.disconnect();} catch (Exception e) {e.printStackTrace();}communications.remove(ip);}}/*** @description: 移除所有连接对象* @author * @date 2023/6/19 15:14* @version 1.0*/public void removeAllCommunication(){for (String ipAddress : communications.keySet()) {removeCommunication(ipAddress);}}}


服务器端实现抽象类创建SocketServer类

/*** @author * @version 1.0* @description: socket 服务启动类* @date 2023/6/19 15:53*/
public class SocketServer extends AbstractSocketServer {public SocketServer(String ipAddress, int port) {super(ipAddress, port);}public SocketServer(int port) {super(port);}
}


客户端通讯接口ICommunication主要用于读写socket交互数据

public interface ICommunication {/*** @description: 获取当前连接的socket对象* @author * @date 2023/6/19 14:28* @version 1.0*/public Socket getSocket();/*** @description: socket创建成功后读取数据* @author * @date 2023/6/19 14:29* @version 1.0*/public void handle() throws Exception;/*** @description: 将读取到的数据统一处理* @author * @date 2023/6/19 14:29* @version 1.0*/public void receive(Socket socket,byte[] data) throws Exception;/*** @description: 发送数据* @author * @date 2023/6/19 14:41* @version 1.0*/public void send(byte[] data) throws Exception;/*** @description: 断开连接* @author liangxuelong* @date 2023/6/19 14:42* @version 1.0*/public void disconnect() throws Exception;
}



客户端实现通讯接口ICommunication创建SocketCommunication对象用于读写处理接收发送和发送数据

/*** @author * @version 1.0* @description: socket 连接对象* 主要用于对已连接的客户端收发消息* @date 2023/6/19 14:43*/
public class SocketCommunication implements ICommunication{private Socket socket; //已经连接的客户端对象private AbstractSocketServer socketServer; //来自哪个服务器,创建的服务器对象public SocketCommunication(@NotNull Socket socket, AbstractSocketServer socketServer) {this.socket = socket;this.socketServer = socketServer;}@Overridepublic Socket getSocket() {return socket;}@Overridepublic void handle() throws Exception {try {System.out.println(socket.getInetAddress().getHostAddress()+" 已连接");InputStream in = socket.getInputStream();ByteArrayOutputStream output = new ByteArrayOutputStream();byte[] b = new byte[1024];int len;while ( (len = in.read(b)) != -1) {output.write(b, 0, len);try {Thread.sleep(10);} catch (InterruptedException e1) {e1.printStackTrace();}if(in.available() == 0) {this.receive(socket,output.toByteArray());output.reset();}b = new byte[1024];len = 0;}} catch (IOException ioException) {throw ioException;}}/*** @description: 接收数据,对客户端接收的数据进行统一处理* 可以编写相应的处理逻辑,我这里是服务器端收到消息后。回复当前连接数量、* @author * @date 2023/6/19 17:30* @version 1.0*/@Overridepublic void receive(Socket socket, byte[] data) throws Exception {//服务器接收客户端消息System.out.println(socket.getInetAddress().getHostAddress()+" 发送:"+new String(data,"gbk"));//服务器回复客户端消息String msg = "当前连接数量:"+socketServer.getConnectSize();socketServer.send(socket.getInetAddress().getHostAddress(),msg.getBytes("gbk"));}/*** @description: 发送数据* @author * @date 2023/6/19 17:30* @version 1.0*/@Overridepublic void send(byte[] data) throws Exception {socket.getOutputStream().write(data);}/*** @description: 断开连接* @author * @date 2023/6/19 17:30* @version 1.0*/@Overridepublic void disconnect() throws Exception {System.out.println(socket.getInetAddress().getHostAddress()+" 已断开");socket.close();}}



定义一个自定义异常ConnectException处理连接数超出最大限制

/*** @author * @version 1.0* @description:* @date 2023/6/19 16:25*/
public class ConnectException extends Exception{public ConnectException(int maxSize) {super("连接数量超出最大限制,连接失败! 当前最大连接数:"+maxSize);}
}


最后定义main方法进行测试

/*** @author * @version 1.0* @description: TODO* @date 2024/2/9 15:57*/
public class Main {public static void main(String[] args) {SocketServer server = new SocketServer("192.168.0.100",5032);server.setMaxConnectSize(2); //设置最大连接数量server.startServer();//每5秒钟获取一下当前连接,并发送数据new Thread(() -> {while (true) {//获取所有连接for (String ip : server.getConnectIpAddress()) {try {System.out.println("当前已连接ip:"+ip);String msg = "向指定客户端发送消息: "+ip+" 你好";//向指定ip发送消息if (server.send(ip,msg.getBytes("gbk"))) {System.out.println("向 "+ip+" 发送了 ["+msg+"]");}} catch (UnsupportedEncodingException e) {e.printStackTrace();}}try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}

相关文章:

Java Socket Server TCP服务端向指定客户端发送消息

实现思路 首先需要知道java里如何创建一个Socket服务器端。 //创建一个服务器端对象ServerSocket server new ServerSocket(); //绑定启动的ip和端口号server.bind(new InetSocketAddress("127.0.0.1",8082));//启动成功后&#xff0c;调用accept()方法阻塞&#xf…...

java日志框架总结(五、logback日志框架)

一、logback概述 Logback是由log4j创始人设计的又一个开源日志组件。 Logback当前分成三个模块&#xff1a; 1、logback-core, 2、logback- classic 3、logback-access。 1&#xff09;logback-core是其它两个模块的基础模块。 2&#xff09;logback-…...

android下library打包aar并上传到maven,嵌入版的app

android嵌入版 准备工作简化代码到三方app上传maven自动打包上面已经完成了library到三方app的流程 这几天在研究android下怎么把自己的项目当作一个library给到另一个app做嵌入使用&#xff0c;把这些记录下来&#xff0c;方便以后参考 准备工作 1.需要了解一些gradle 命令打…...

Xampp中Xdebug的安装使用

工欲善其事&#xff0c;必先利其器 XDebug简介 XDebug 是一个用于 PHP 的调试和性能分析工具。它提供了一系列功能&#xff0c;帮助开发者在开发和调试 PHP 应用程序时更加高效。 以下是 XDebug 的一些主要特性和功能&#xff1a; 调试功能&#xff1a; 断点调试&#xff1a;…...

金融行业的软件测试分析

随着金融行业的业务不断增加&#xff0c;金融交易模式的不断变化&#xff0c;金融机构对信息化的要求也越来越高&#xff0c;高质量的金融软件对于金融机构来说显得尤为重要。如何保证金融行业软件的质量&#xff0c;对金融行业软件的测试人员来说&#xff0c;也提出了更高的要…...

踩坑了,MySQL数据库生成大量奇怪的大文件

作者&#xff1a;田逸&#xff08;formyz&#xff09; 一大早就收到某个数据库服务器磁盘满的报警信息&#xff0c;其中数据盘使用率超过90%&#xff0c;如下图所示。 这是一台刚上线不久的MySQL从库服务器&#xff0c;数据盘的总容量是300G。先登录系统&#xff0c;查看主从同…...

ctfshow-web11~20-WP

web11 根据提示,查询对ctfshow域名进行dns查询,查看TXT记录 阿里云查询链接:阿里云网站运维检测平台 获取flag成功 web12 根据题目提示,我们访问robots.txt,获取到后台地址 然后我们访问一下后台...

2.5学习总结9

并查集 知识点 并查集是一种数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题。它支持两种操作&#xff1a; Find(x)&#xff1a;查找元素 x 所属的集合。Union(x, y)&#xff1a;将元素 x 所属的集合和元素 y 所属的集合合并。 初始化&#xff1a;将每个元素单…...

删除.git的影响、git分支切换时注意事项

一、删除.git的影响 master分支文件 dev分支文件 删除.git后 文件为删除.git前分支的文件状态。 二、git分支切换时注意事项 情景&#xff1a;如果我在分支A&#xff0c;想要跳转到分支B。 git的规矩是&#xff0c;在那个分支上进行的提交&#xff0c;就算哪个分支上的工作…...

Linux系统调试课:硬件断点

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在linux内核编程中,经常会遇到由于内存被篡改,例如 buffer overflow,野指针,write after free等。查找分析此类问题非常的麻烦。 一、什么是硬件断点 硬件断点,是Linux内核中是一种被ptrace和内核内调试器使用调试…...

百卓Smart管理平台 uploadfile.php 文件上传漏洞复现(CVE-2024-0939)

0x01 产品简介 百卓Smart管理平台是北京百卓网络技术有限公司(以下简称百卓网络)的一款安全网关产品,是一家致力于构建下一代安全互联网的高科技企业。 0x02 漏洞概述 百卓Smart管理平台 uploadfile.php 接口存在任意文件上传漏洞。未经身份验证的攻击者可以利用此漏洞上传…...

关于RabbitMQ常见的十道面试题

RabbitMQ是如何组成的&#xff1f;它有哪些重要的组件&#xff1f; RabbitMQ主要由以下几个重要组件组成&#xff1a; Broker&#xff1a;这是消息代理&#xff0c;主要负责接收、存储和转发消息Exchanges&#xff1a;交换器&#xff0c;它的主要作用是根据一定的规则匹配消息…...

spring cloud stream

背景 主要解决不同消息中间件切换问题。实现不同中间件的代码解耦。 链接: 支持的中间件 后文使用kafka测试。 引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-stream</artifactId></depende…...

vue3 之 组合式API—watch函数

watch函数 作用&#xff1a;侦听一个或者多个数据的变化&#xff0c;数据变化时执行回调函数 两个额外参数&#xff1a; 1.immediate&#xff08;立即执行&#xff09;2.deep&#xff08;深度侦听&#xff09; 场景&#xff1a;比如选择不同的内容请求后端不同数据时 如下图 …...

并发容器【ConcurentHashMap、CopyOnWriteArrayList、阻塞队列、ArrayBlockingQueue】

并发容器 什么是并发容器?同步容器:并发容器: ConcurrentHashMap结构图JDK1.7结构图JDK1.8结构图 CopyOnWriteArrayList实现原理 并发队列阻塞队列ArrayBlockingQueue 转自极客时间 什么是并发容器? 在JUC包中&#xff0c;有一大部分是关于并发容器的&#xff0c;如Concurr…...

EmoLLM-心理健康大模型

宣传一下自己最近参与的开源 https://github.com/aJupyter/EmoLLM EmoLLM-心理健康大模型 EmoLLM 探索本项目的文档 查看Demo 报告Bug 提出新特性 EmoLLM 是一个能够支持 理解用户-支持用户-帮助用户 心理健康辅导链路的心理健康大模型&#xff0c;由 InternLM2 指令微…...

学成在线:采用XXL-JOB任务调度方案使用FFmpeg处理视频转码业务

分片技术方案 概述 XXL-JOB并不直接提供数据处理的功能&#xff0c;它只会给所有注册的执行器分配好分片序号&#xff0c;在向执行器下发任务调度的同时携带分片总数和当前分片序号等参数 设计作业分片方案保证多个执行器之间不会查询到重复的任务,保证任务不会重复执行 任…...

计算机毕业设计 | SpringBoot大型旅游网站 旅行后台管理系统(附源码)

1&#xff0c; 概述 1.1 项目背景 随着互联网技术的快速发展和普及&#xff0c;旅游行业逐渐转向线上&#xff0c;越来越多的游客选择在线预订旅游产品。传统的线下旅行社模式已不能满足市场需求&#xff0c;因此&#xff0c;开发一个高效、便捷的旅游网站成为行业的迫切需求…...

蓝桥杯----凑算式

这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。 比如: 68/3952/714 就是一种解法, 53/1972/486 是另一种解法. 这个算式一共有多少种解法? 注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。 代码 public class _03凑算式 {static int a[] {1,2,3…...

JCTC | 利用几何深度学习对蛋白质-配体结合pose进行等变灵活建模

Overview 该论文解决了药物开发中蛋白质-配体复合结构灵活建模的挑战。作者提出了一种名为FlexPose的新型深度学习框架&#xff0c;它可以直接对复杂结构进行建模&#xff0c;而不需要传统的采样和评分策略。 该模型结合了标量-向量双特征表示和 SE(3)等变网络设计来处理动态结…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道

文/法律实务观察组 在债务重组领域&#xff0c;专业机构的核心价值不仅在于减轻债务数字&#xff0c;更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明&#xff0c;合法债务优化需同步实现三重平衡&#xff1a; 法律刚性&#xff08;债…...

前端调试HTTP状态码

1xx&#xff08;信息类状态码&#xff09; 这类状态码表示临时响应&#xff0c;需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分&#xff0c;客户端应继续发送剩余部分。 2xx&#xff08;成功类状态码&#xff09; 表示请求已成功被服务器接收、理解并处…...

LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考

目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候&#xff0c;显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...