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)等变网络设计来处理动态结…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
