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));//启动成功后,调用accept()方法阻塞…...
java日志框架总结(五、logback日志框架)
一、logback概述 Logback是由log4j创始人设计的又一个开源日志组件。 Logback当前分成三个模块: 1、logback-core, 2、logback- classic 3、logback-access。 1)logback-core是其它两个模块的基础模块。 2)logback-…...
android下library打包aar并上传到maven,嵌入版的app
android嵌入版 准备工作简化代码到三方app上传maven自动打包上面已经完成了library到三方app的流程 这几天在研究android下怎么把自己的项目当作一个library给到另一个app做嵌入使用,把这些记录下来,方便以后参考 准备工作 1.需要了解一些gradle 命令打…...
Xampp中Xdebug的安装使用
工欲善其事,必先利其器 XDebug简介 XDebug 是一个用于 PHP 的调试和性能分析工具。它提供了一系列功能,帮助开发者在开发和调试 PHP 应用程序时更加高效。 以下是 XDebug 的一些主要特性和功能: 调试功能: 断点调试:…...
金融行业的软件测试分析
随着金融行业的业务不断增加,金融交易模式的不断变化,金融机构对信息化的要求也越来越高,高质量的金融软件对于金融机构来说显得尤为重要。如何保证金融行业软件的质量,对金融行业软件的测试人员来说,也提出了更高的要…...
踩坑了,MySQL数据库生成大量奇怪的大文件
作者:田逸(formyz) 一大早就收到某个数据库服务器磁盘满的报警信息,其中数据盘使用率超过90%,如下图所示。 这是一台刚上线不久的MySQL从库服务器,数据盘的总容量是300G。先登录系统,查看主从同…...
ctfshow-web11~20-WP
web11 根据提示,查询对ctfshow域名进行dns查询,查看TXT记录 阿里云查询链接:阿里云网站运维检测平台 获取flag成功 web12 根据题目提示,我们访问robots.txt,获取到后台地址 然后我们访问一下后台...
2.5学习总结9
并查集 知识点 并查集是一种数据结构,用于处理一些不相交集合的合并及查询问题。它支持两种操作: Find(x):查找元素 x 所属的集合。Union(x, y):将元素 x 所属的集合和元素 y 所属的集合合并。 初始化:将每个元素单…...
删除.git的影响、git分支切换时注意事项
一、删除.git的影响 master分支文件 dev分支文件 删除.git后 文件为删除.git前分支的文件状态。 二、git分支切换时注意事项 情景:如果我在分支A,想要跳转到分支B。 git的规矩是,在那个分支上进行的提交,就算哪个分支上的工作…...
Linux系统调试课:硬件断点
沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在linux内核编程中,经常会遇到由于内存被篡改,例如 buffer overflow,野指针,write after free等。查找分析此类问题非常的麻烦。 一、什么是硬件断点 硬件断点,是Linux内核中是一种被ptrace和内核内调试器使用调试…...
百卓Smart管理平台 uploadfile.php 文件上传漏洞复现(CVE-2024-0939)
0x01 产品简介 百卓Smart管理平台是北京百卓网络技术有限公司(以下简称百卓网络)的一款安全网关产品,是一家致力于构建下一代安全互联网的高科技企业。 0x02 漏洞概述 百卓Smart管理平台 uploadfile.php 接口存在任意文件上传漏洞。未经身份验证的攻击者可以利用此漏洞上传…...
关于RabbitMQ常见的十道面试题
RabbitMQ是如何组成的?它有哪些重要的组件? RabbitMQ主要由以下几个重要组件组成: Broker:这是消息代理,主要负责接收、存储和转发消息Exchanges:交换器,它的主要作用是根据一定的规则匹配消息…...
spring cloud stream
背景 主要解决不同消息中间件切换问题。实现不同中间件的代码解耦。 链接: 支持的中间件 后文使用kafka测试。 引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-stream</artifactId></depende…...
vue3 之 组合式API—watch函数
watch函数 作用:侦听一个或者多个数据的变化,数据变化时执行回调函数 两个额外参数: 1.immediate(立即执行)2.deep(深度侦听) 场景:比如选择不同的内容请求后端不同数据时 如下图 …...
并发容器【ConcurentHashMap、CopyOnWriteArrayList、阻塞队列、ArrayBlockingQueue】
并发容器 什么是并发容器?同步容器:并发容器: ConcurrentHashMap结构图JDK1.7结构图JDK1.8结构图 CopyOnWriteArrayList实现原理 并发队列阻塞队列ArrayBlockingQueue 转自极客时间 什么是并发容器? 在JUC包中,有一大部分是关于并发容器的,如Concurr…...
EmoLLM-心理健康大模型
宣传一下自己最近参与的开源 https://github.com/aJupyter/EmoLLM EmoLLM-心理健康大模型 EmoLLM 探索本项目的文档 查看Demo 报告Bug 提出新特性 EmoLLM 是一个能够支持 理解用户-支持用户-帮助用户 心理健康辅导链路的心理健康大模型,由 InternLM2 指令微…...
学成在线:采用XXL-JOB任务调度方案使用FFmpeg处理视频转码业务
分片技术方案 概述 XXL-JOB并不直接提供数据处理的功能,它只会给所有注册的执行器分配好分片序号,在向执行器下发任务调度的同时携带分片总数和当前分片序号等参数 设计作业分片方案保证多个执行器之间不会查询到重复的任务,保证任务不会重复执行 任…...
计算机毕业设计 | SpringBoot大型旅游网站 旅行后台管理系统(附源码)
1, 概述 1.1 项目背景 随着互联网技术的快速发展和普及,旅游行业逐渐转向线上,越来越多的游客选择在线预订旅游产品。传统的线下旅行社模式已不能满足市场需求,因此,开发一个高效、便捷的旅游网站成为行业的迫切需求…...
蓝桥杯----凑算式
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。 比如: 68/3952/714 就是一种解法, 53/1972/486 是另一种解法. 这个算式一共有多少种解法? 注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。 代码 public class _03凑算式 {static int a[] {1,2,3…...
JCTC | 利用几何深度学习对蛋白质-配体结合pose进行等变灵活建模
Overview 该论文解决了药物开发中蛋白质-配体复合结构灵活建模的挑战。作者提出了一种名为FlexPose的新型深度学习框架,它可以直接对复杂结构进行建模,而不需要传统的采样和评分策略。 该模型结合了标量-向量双特征表示和 SE(3)等变网络设计来处理动态结…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
虚拟机网络不通的问题(这里以win10的问题为主,模式NAT)
当我们网关配置好了,DNS也配置好了,最后在虚拟机里还是无法访问百度的网址。 第一种情况: 我们先考虑一下,网关的IP是否和虚拟机编辑器里的IP一样不,如果不一样需要更改一下,因为我们访问百度需要从物理机…...
关于疲劳分析的各种方法
疲劳寿命预测方法很多。按疲劳裂纹形成寿命预测的基本假定和控制参数,可分为名义应力法、局部应力一应变法、能量法、场强法等。 1名义应力法 名义应力法是以结构的名义应力为试验和寿命估算的基础,采用雨流法取出一个个相互独立、互不相关的应力循环&…...
< 自用文 OS有关 新的JD云主机> 国内 京东云主机 2C4G 60G 5Mb 498/36月 Ubuntu22
攒了这么久,废话一些: 前几周很多事儿,打算回北京,开个清真的德克萨斯烤肉店,写了一篇 : < 自用文 Texas style Smoker > 美式德克萨斯烟熏炉 从设计到实现 (第一部分&…...
matlab模糊控制实现路径规划
路径规划是机器人和自动驾驶系统中的重要问题之一,它涉及确定如何在给定环境中找到最优路径以达到特定目标。模糊控制是一种有效的控制方法,可以应用于路径规划问题。 路径规划算法的目标是在避免障碍物的情况下,找到机器人或车辆从起点到终…...
C++核心编程_继承同名成员处理方式
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢? 访问子类同名成员 直接访问即可 访问父类同名成员 需要加作用域 class Base { public:Base(){m_A 100;}void func(){cout << "B…...
