简单的springboot 编写Socket服务接口
简单的springboot 编写Socket服务接口
1.需求
我们项目中有部分老接口为票据接口,其中实现为java socket形式进行实现,但是其中大部分信息都是原始公司封装的包进行实现的,想要修改非常费劲,所以此处简单了解了一下socket,自己简单的 编写了两个测试接口,方便以后如果需要自己添加socket接口,可以快速编写。
2. 简单实现
编写的接口为测试接口,整体结构相对简单,主要就是客户端发起一个请求,请求信息前6位为请求串长度,其余为请求的请求体,发送信息到服务端后,服务端使用线程池异步处理信息,最终返回处理之后的响应信息,客户端则接收响应信息,同样的步骤处理响应信息,前6位为响应信息长度,然后解析响应信息即可,因为为简单案例,所以没有进行数据通信加密。
2.1 客户端实现
客户端代码相对简单,直接写入到controller当中了,具体实现代码如下:
package cn.git.controller;import cn.git.entity.Product;
import cn.git.socket.SocketUtil;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.net.Socket;/*** @description: Socket测试controller* @program: bank-credit-sy* @author: lixuchun* @create: 2023-03-20*/
@RestController
@RequestMapping("/socket")
public class SocketController {/*** 异步发送200个请求,模拟多用户*/@GetMapping("/client")public String client() {// 异步发送200个请求,模拟多用户for (int i = 0; i < 200; i++) {int finalI = i;new Thread(()-> {try {// 创建Socket对象Socket socket = new Socket("localhost", 7777);// 设置超时时间socket.setSoTimeout(60000);// 测试产品Product product = new Product();product.setAmount(new BigDecimal(finalI));product.setCycle(12);product.setEndTime("2018-08-08");product.setName("test");product.setRate(new BigDecimal(1));product.setRaised(new BigDecimal(0));// 拼接请求报文String message = JSONObject.toJSONString(product);String reqLengthStr = SocketUtil.leftFixedZero(6, message.length());// 发送请求报文PrintStream out = new PrintStream(socket.getOutputStream());out.println(reqLengthStr.concat(message));// 获取服务端返回的消息长度信息BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));char[] lengthByte = new char[6];in.read(lengthByte);String rspLengthStr = new String(lengthByte);int responseLength = Integer.parseInt(rspLengthStr);// 获取服务端返回的消息体信息char[] responseByte = new char[responseLength];in.read(responseByte);String responseBody = new String(responseByte);// 打印返回结果System.out.println("返回结果为 : ".concat(responseBody));socket.close();} catch (Exception e) {e.printStackTrace();}}).start();}return "处理成功啦";}}
2.2 服务端代码
服务端代码相对复杂一些,主要有socket服务初始化,公共线程池,工具类以及接口处理handle类。具体实现如下:
-
socket初始化类
package cn.git.socket;import cn.git.mapper.ProductMapper; import cn.git.socket.handler.SocketHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;import javax.annotation.PostConstruct; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;/*** @description: socket接口入口信息* @program: bank-credit-sy* @author: lixuchun* @create: 2023-03-20*/ @Slf4j @Component public class CustomSocketServer {@Autowiredprivate ProductMapper productMapper;/*** 初始化调用接口* * 异步启动socket监听服务,端口 7777*/@PostConstructpublic void socketServerInit() throws IOException {new Thread(() -> {try {// 监听7777端口log.info("开始启动socket服务信息,端口监听 7777");ServerSocket serverSocket = new ServerSocket(7777);// 循环监听while (true) {log.info("等待客户端连接...");Socket clientSocket = serverSocket.accept();ThreadPoolUtil.THREAD_POOL.execute(// 构建handlerSocketHandler.builder().clientSocket(clientSocket).productMapper(productMapper).build());log.info("客户端连接成功,当前连接数:{}", ThreadPoolUtil.THREAD_POOL.getActiveCount());}} catch (Exception e) {e.printStackTrace();}}).start();} } -
通用线程池相关类
自定义线程池工厂实现如下package cn.git.socket;import cn.hutool.core.util.StrUtil;import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger;/*** 自定义线程池工厂* @program: bank-credit-sy* @author: lixuchun* @create: 2021-12-25*/ public class OnlineThreadFactory implements ThreadFactory {/*** 自增线程序号*/private final AtomicInteger threadNumber = new AtomicInteger(1);/*** 线程名称前缀*/private final String threadNamePrefix;/*** 构造方法* @param threadNamePrefix 方法前缀*/public OnlineThreadFactory(String threadNamePrefix) {this.threadNamePrefix = threadNamePrefix.concat(StrUtil.DASHED);}/*** Constructs a new {@code Thread}. Implementations may also initialize* priority, name, daemon status, {@code ThreadGroup}, etc.* @param runnable a runnable to be executed by new thread instance* @return constructed thread, or {@code null} if the request to* create a thread is rejected*/@Overridepublic Thread newThread(Runnable runnable) {// 设置线程池名称Thread thread = new Thread(runnable , threadNamePrefix.concat(StrUtil.toString(threadNumber.getAndIncrement())));// 设置守护线程if (thread.isDaemon()) {thread.setDaemon(false);}// 同意设置程默认优先级 5if (thread.getPriority() != Thread.NORM_PRIORITY) {thread.setPriority(Thread.NORM_PRIORITY);}return thread;} }线程池工具类
package cn.git.socket;import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit;/*** @description: 线程池工具类* @program: bank-credit-sy* @author: lixuchun* @create: 2022-08-16 10:58:07*/ public class ThreadPoolUtil {/*** 线程池线程名称*/private static final String DICS_THREAD_POOL_PREFIX = "DICS-SOCKET";/*** 超时时间 单位毫秒*/private static final int REQ_TIME_OUT = 10 * 1000;/*** 阻塞队列大小*/private static final int QUEUE_SIZE = 200;/*** 核心线程池数量*/private static final int CORE_THREAD_NUM = 5;/*** 最大线程池数量*/private static final int MAX_THREAD_NUM = 20;/*** 线程池构造参数*/public static ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(CORE_THREAD_NUM,MAX_THREAD_NUM,REQ_TIME_OUT,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(QUEUE_SIZE),new OnlineThreadFactory(DICS_THREAD_POOL_PREFIX)); } -
业务处理handle类
package cn.git.socket.handler;import cn.git.entity.Product; import cn.git.mapper.ProductMapper; import cn.git.socket.SocketUtil; import cn.hutool.core.util.IdUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.*;import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket;/*** @description: socket请求处理类* @program: bank-credit-sy* @author: lixuchun* @create: 2023-03-20*/ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class SocketHandler implements Runnable {/*** 订单信息mapper*/private ProductMapper productMapper;/*** 客户端socket*/private Socket clientSocket;/*** When an object implementing interface <code>Runnable</code> is used* to create a thread, starting the thread causes the object's* <code>run</code> method to be called in that separately executing* thread.* <p>* The general contract of the method <code>run</code> is that it may* take any action whatsoever.** @see Thread#run()*/@SneakyThrows@Overridepublic void run() {// 获取请求数据信息System.out.println("接收数据开始处理!");BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);// 读取数据前6位,获取请求数据长度char[] bodyBytes = new char[6];in.read(bodyBytes);String dataLengthStr = new String(bodyBytes);// 获取请求数据信息Integer dataLength = Integer.parseInt(dataLengthStr);System.out.println("请求数据长度:" + dataLength);bodyBytes = new char[dataLength];in.read(bodyBytes);String requestBodyInfo = new String(bodyBytes);System.out.println("请求数据:" + requestBodyInfo);// 请求数据转换为Person对象Product product = JSON.parseObject(requestBodyInfo, Product.class);product.setId(IdUtil.simpleUUID());productMapper.insert(product);// 响应数据String rspJSONInfo = JSONObject.toJSONString(product);// 响应数据长度标识位 eg: 000667String prefixLength = SocketUtil.leftFixedZero(6, rspJSONInfo.length());// 最终响应数据String finalRspInfo = prefixLength.concat(rspJSONInfo);System.out.println("响应数据:" + finalRspInfo);out.println(finalRspInfo);} } -
socket工具类
package cn.git.socket;/*** @description: socket工具类* @program: bank-credit-sy* @author: lixuchun* @create: 2023-03-20*/ public class SocketUtil {/*** 左补0* eg: length = 6, num = 123, return 000123** @param length 长度* @param num 数字* @return*/public static String leftFixedZero(int length, int num) {return String.format("%0" + length + "d", num);}}
3.测试
启动服务,观察socket监听端口 7777 是否正常启动监听,观察如下,socket服务端正常启动监听端口

开始模拟多客户端调用,请求 http://localhost:8088/socket/client 接口,循环异步发起 200 socket 请求。

观察后台信息

观察数据库,发现数据已经正确导入了, 成功插入了 200 条数据信息

相关文章:
简单的springboot 编写Socket服务接口
简单的springboot 编写Socket服务接口 1.需求 我们项目中有部分老接口为票据接口,其中实现为java socket形式进行实现,但是其中大部分信息都是原始公司封装的包进行实现的,想要修改非常费劲,所以此处简单了解了一下socket&#…...
【Android 源码分析】Activity短暂的一生 -- 目录篇 (持续更新)
1. 前言 忽然有一天,我想要做一件事:去代码中去验证那些曾经被“灌输”的理论。 …...
VS Code使用Git Bash终端
Git Bash可以运行linux命令,在VS Code的终端界面,找到号旁边的箭头,就能直接切换了 当然,前提是安装了Git Bash,并且在资源管理器里,能鼠标右键出"Git Bash Here"...
移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——13.mapset(模拟实现)
1.对红黑树进行改造 1.1treenode模板参数改变 之前构建treenode模板参数传的是class k,class v(set为k,k;map是k,v),现在直接用T代替 template<class T> //这里直接传了T作为模板参数,T可能是pai…...
【C++】多态(下)
个人主页~ 多态(上)~ 多态 四、多态的原理1、虚表的存储位置2、多态的原理3、动态绑定和静态绑定 五、单继承和多继承关系的虚函数表1、单继承中的虚函数表2、多继承中的虚函数表 六、多态中的一些小tips 四、多态的原理 1、虚表的存储位置 class A {…...
基于四种网络结构的WISDM数据集仿真及对比:Resnet、LSTM、Shufflenet及CNN
在上节中,我们已经详细介绍了WISDM数据集及如何使用CNN网络训练,得到了六个维度的模型仿真指标及五个维度的可视化分析,那么现在我们将训练模型推广到其他网路结构中去,通过仿真实验来对比一下不同网络之间对于WISDM数据集的训练效…...
【蚂蚁HR-注册/登录安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...
【分布式微服务云原生】详解Redis的主从模式,主服务器挂了如何从多个从服务器选出新的主服务器
深入探索Redis主从模式:架构、故障转移与最佳实践 摘要: 本文深入探讨了Redis的主从复制模式,包括其工作原理、故障转移机制以及如何配置和管理这一模式。文章通过清晰的结构和实例代码,帮助读者理解如何在实际项目中应用Redis主…...
Android Context是什么?有很多的context他们之间有什么区别?什么时候该使用哪个?
目录 一、Context是什么? 在Android中,Context是一个抽象类 ,它代表了应用程序的当前状态,包括资源和类加载器等,它提供了一个应用运行所需的信息,比如我们要获取资源 ,那么需要她,…...
数字解调同步技术
一些概念 载波同步 载波同步是一个过程,通过该过程,接收机使其本地载波振荡器的频率和相位与接收信号的频率和相位相适应。 载波相位同步 Carrier Phase Synchronization载波频率同步 Carrier Frequency Synchronization 帧同步 待更新 位同步 待…...
k8s搭建一主三从的mysql8集群---无坑
一,环境准备 1.1 k8s集群服务器 ip角色系统主机名cpumem192.168.40.129mastercentos7.9k8smaster48192.168.40.130node1centos7.9k8snode148192.168.40.131node2centos7.9k8snode248192.168.40.132node3centos7.9k8snode348 k8s集群操作请参考《K8s安装部署&…...
Oracle架构之物理存储中各种文件详解
文章目录 1 物理存储1.1 简介1.2 数据文件(data files)1.2.1 定义1.2.2 分类1.2.2.1 系统数据文件1.2.2.2 撤销数据文件1.2.2.3 用户数据文件1.2.2.4 临时数据文件 1.3 控制文件(Control files)1.3.1 定义1.3.2 查看控制文件1.3.3…...
AR 领域的突破——微型化显示屏为主流 AR 眼镜铺平道路
概述 多年来,增强现实 (AR) 技术一直吸引着人们的想象力,有望将数字信息与我们的物理世界无缝融合。通过将计算机生成的图像叠加到现实世界的视图上,AR 有可能彻底改变我们与环境的互动方式。从增强游戏体验到协助手术室的外科医生ÿ…...
Web安全 - 构建全面的业务安全保护防御体系
文章目录 业务安全概述业务安全 vs. 基础安全业务安全的防护业务安全的防护策略1. 用户资源对抗的技术实现与优化2. IP资源对抗的技术实现与优化3. 设备资源对抗的技术实现与优化4. 操作资源对抗的技术实现与优化实际应用场景中的策略 典型场景业务场景 1:新用户注册…...
机器学习(2):机器学习的相关术语
场景示例: 你周日约了小李、老王打牌,小李先来了,老王没来。你想打电话叫老王过来。小李说:“你别打电话啦,昨天老王喜欢的球队皇马输球了,他的项目在上个礼拜也没成功上线,再加上他儿子期末考…...
Leecode热题100-75.颜色分类
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 必须在不使用库内置的 sort 函数的情况下解…...
408算法题leetcode--第22天
200. 岛屿数量 200. 岛屿数量时间:O(mn);空间:O(min(m, n)),队列最大入队个数,可以想象从左上到右下,第一次入队1个,第二次出队1,入队2,第三次出队2,入队3……...
dubbo微服务
一.启动nacos和redis 1.虚拟机查看是否开启nacos和redis docker ps2.查看是否安装nacos和redis docker ps -a3.启动nacos和redis docker start nacos docker start redis-6379 docker ps二.创建三个idea的maven项目 1.第一个项目dubboapidemo 2.1.1向pom.xml里添加依赖 …...
如何在 DAX 中计算多个周期的移动平均线
在 DAX 中计算移动聚合很容易。但是,计算一段时间内的移动平均值时会有一些陷阱。由于其中一些陷阱是定义问题,因此我们必须小心,不要选择错误的方法。让我们看看细节。欢迎来到雲闪世界。 添加图片注释,不超过 140 字(…...
微信小程序 图片的上传
错误示范 /*从相册中选择文件 微信小程序*/chooseImage(){wx.chooseMedia({count: 9,mediaType: [image],sourceType: [album],success(res) {wx.request({url:"发送的端口占位符",data:res.tempFiles[0].tempFilePath,method:POST,success(res){//请求成功后应该返…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
