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

java socket bio 改造为 netty nio

        公司早些时候接入一款健康监测设备,由于业务原因近日把端口暴露在公网后,每当被恶意连接时系统会创建大量线程,在排查问题是发现是使用了厂家提供的服务端demo代码,在代码中使用的是java 原生socket,在发现连接后使用独立线程处理后续通信,占用系统资源造成了服务宕机,因此需要进行改造。

        厂家提供的demo代码如下:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;public class Demo {public static void main(String[] args) {int port = 8003;if (args.length == 1) {port = Integer.parseInt(args[0]);}ServerSocket ss;try {ss = new ServerSocket(port);}catch (Exception e) {System.out.println("服务端socket失败 port = " + port);return;}System.out.println("启动socket监听 端口:" + port);List<Socket> socketList = new ArrayList<>();while (true) {try {Socket socket = ss.accept();if (socket == null || socket.isClosed()) {socketList.remove(socket);continue;}if (socketList.contains(socket)) {continue;}socketList.add(socket);System.out.println("socket连接 address = " + socket.getInetAddress().toString() + " port = " + socket.getPort());new Thread(new HealthReadThread(socket)).start();}catch (IOException e) {System.out.println(e.getMessage());}}}
}
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;public class HealthReadThread implements Runnable {private Socket socket;HealthReadThread(Socket socket) {this.socket = socket;}private static String message = "";@Overridepublic void run() {try {//输入InputStream inPutStream = socket.getInputStream();BufferedInputStream bis = new BufferedInputStream(inPutStream);
//            BufferedReader br = new BufferedReader(new InputStreamReader(inPutStream));//输出OutputStream outputStream = socket.getOutputStream();BufferedOutputStream bw = new BufferedOutputStream(outputStream);String ip = socket.getInetAddress().getHostAddress();int port = socket.getPort();String readStr = "";
//            char[] buf;byte[] buf;int readLen = 0;while (true) {if (socket.isClosed()) {break;}buf = new byte[1024];try {readLen = bis.read(buf);if (readLen <= 0) {
//                        System.out.println(Thread.currentThread().getId() + "线程: " + "ip地址:" + ip + " 端口地址:" + port + "暂无接收数据");continue;}System.out.println(Thread.currentThread().getId() + "线程: " + "ip地址:" + ip + " 端口地址:" + port + " 接收到原始命令长度:" + readLen);readStr = StringUtils.byteToHexString(buf, readLen);
//                    readStr = new String(buf ,0 , readLen);} catch (IOException e) {System.out.println(e.getMessage());socket.close();
//                    continue;}if (readStr == null || "".equals(readStr)) {continue;}// 省略业务代码}}catch (Exception e) {System.out.println(e.getMessage());}}
}

使用netty进行改造:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Slf4j
@Component
public class DeviceNettyServer implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {start();}public void start() {Thread thread = new Thread(() -> {// 配置服务端的NIO线程组EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup(4);ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup)// 使用 NIO 方式进行网络通信.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) throws Exception {// 添加自己的处理器ch.pipeline().addLast(new DeviceMsgHandler());}});try {int port1 = 8081;int port2 = 8082;// 绑定一个端口并且同步,生成一个ChannelFuture对象ChannelFuture f1 = b.bind(port1).sync();ChannelFuture f2 = b.bind(port2).sync();log.info("启动监听, 端口:" + port1 + "、" + port2);// 对关闭通道进行监听f1.channel().closeFuture().sync();f2.channel().closeFuture().sync();} catch (Exception e) {log.error("启动监听失败", e);} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();}});thread.setName("DeviceNettyServer");thread.start();}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;import java.util.*;
import java.util.concurrent.ConcurrentHashMap;@Slf4j
public class DeviceMsgHandler extends SimpleChannelInboundHandler<ByteBuf> {/*** 已连接的设备*/private static final ConcurrentHashMap<Channel, DeviceDTO> CONNECTION_DEVICE_MAP = new ConcurrentHashMap<>(8);/*** 一旦连接,第一个被执行*/@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {String remoteAddress = ctx.channel().remoteAddress().toString();log.info("发现连接, remoteAddress: " + remoteAddress);// 发送查询设备信息指令sendQuery(ctx.channel());}/*** 读取数据*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {byte[] bytes = new byte[msg.readableBytes()];msg.readBytes(bytes);// 忽略业务处理代码// 传递给下一个处理器ctx.fireChannelRead(msg);}/*** 连接断开** @param ctx*/@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) {log.info("连接断开, remoteAddress: " + ctx.channel().remoteAddress());CONNECTION_DEVICE_MAP.remove(ctx.channel());}/*** 连接异常** @param ctx* @param cause*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {log.info("连接异常, remoteAddress: " + ctx.channel().remoteAddress());CONNECTION_DEVICE_MAP.remove(ctx.channel());}

经过改造后使用了4个worker线程进行读写,消除了原先恶意连接造成线程数无线扩大的问题,使用nio也极大的提高了系统资源利用率。

相关文章:

java socket bio 改造为 netty nio

公司早些时候接入一款健康监测设备&#xff0c;由于业务原因近日把端口暴露在公网后&#xff0c;每当被恶意连接时系统会创建大量线程&#xff0c;在排查问题是发现是使用了厂家提供的服务端demo代码&#xff0c;在代码中使用的是java 原生socket&#xff0c;在发现连接后使用独…...

进程、线程、协程详解:并发编程的三大武器

在现代计算机科学中,并发编程是一个核心概念,而进程、线程和协程是实现并发的三种主要方式。本文将深入探讨这三种概念,分析它们的特点、优缺点,以及适用场景。 1. 进程 (Process) 1.1 定义 进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的…...

探索5 大 Node.js 功能

目录 单线程 Node.js 工作线程【Worker Threads】 Node.js 进程 进程缺点 工作线程 注意 集群进程模块【Cluster Process Module】 内部发生了什么&#xff1f; 为什么要使用集群 注意&#xff1a; 应用场景&#xff1a; 内置 HTTP/2 支持 这个 HTTP/2 是什么&…...

EZUIKit.js萤石云vue项目使用

EZUIKit.js 是萤石云&#xff08;Ezviz&#xff09;提供的一款用于Web端的视频播放和控制的JavaScript库。它允许开发者在网页上轻松集成视频监控、对讲、录像回放等功能&#xff0c;适用于安防监控、智能家居等场景。通过EZUIKit.js&#xff0c;你可以方便地访问萤石云平台上的…...

【Linux】磁盘分区挂载网络配置进程【更详细,带实操】

Linux全套讲解系列&#xff0c;参考视频-B站韩顺平&#xff0c;本文的讲解更为详细 目录 一、磁盘分区挂载 1、磁盘分区机制 2、增加磁盘应用实例 3、磁盘情况查询 4、磁盘实用指令 二、网络配置 1、NAT网络原理图 2、网络配置指令 3、网络配置实例 4、主机名和host…...

Java 为什么使用 UTF-16 而不是更节省内存的 UTF-8?

Java 选择 UTF-16 编码而不是更节省内存的 UTF-8 这一决定&#xff0c;涉及多个层面的设计权衡&#xff0c;包括历史原因、虚拟机&#xff08;JVM&#xff09;实现的复杂度、性能和字符处理的一致性。要理解这个问题&#xff0c;我们需要从 Java 语言的设计初衷、JVM 的工作机制…...

损失函数篇 | YOLOv10 引入 Inner-IoU 基于辅助边框的IoU损失

作者导读:Inter-IoU:基于辅助边框的IoU损失 论文地址:https://arxiv.org/abs/2311.02877 作者视频解读:https://www.bilibili.com 开源代码地址:https://github.com/malagoutou/Inner-IoU...

夹耳开放式耳机好用吗?一篇文章告诉你答案,附上挑选避坑小知识

夹耳开放式耳机作为音频领域的新兴产品&#xff0c;正逐渐走入大众视野。其独特的设计和功能引发了广泛关注与讨论。究竟夹耳开放式耳机好用吗&#xff1f;在这篇文章中&#xff0c;我们将从专业角度深入剖析他的各个方面。同时&#xff0c;还会为你提供详细的挑选避坑小知识&a…...

WebSocket 2024/9/30

WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传输。 与HTTP协议的区别 实现...

大数据开发--1.1大数据概论

目录 一.大数据的概念 什么是大数据&#xff1f; 二. 大数据的特点 三. 大数据应用场景 四. 大数据分析业务步骤 大数据分析的业务流程&#xff1a; 五.大数据职业规划 职业方向 岗位技术要求 六. 大数据学习路线 一.大数据的概念 什么是大数据&#xff1f; 数据 世界…...

Java | Leetcode Java题解之第438题找到字符串中所有字母异位词

题目&#xff1a; 题解&#xff1a; class Solution {public List<Integer> findAnagrams(String s, String p) {int sLen s.length(), pLen p.length();if (sLen < pLen) {return new ArrayList<Integer>();}List<Integer> ans new ArrayList<Int…...

springboot整合MybatisPlus+MySQL

上一篇&#xff1a;springboot整合sentinel和对feign熔断降级 文章目录 一、准备二、主要工作三、具体步骤3.1 准备数据库环境3.20 pre引入依赖3.2 引入依赖3.3 bootstrap.yml配置mybatisplus3.40 pre引入service、mapper3.4 引入实体类、service、mapper 四、测试目录结构 五…...

【MySQL】视图、用户和权限管理

目录 视图创建视图数据修改影响删除视图视图优点 用户和权限管理查看当前的数据库拥有用户信息创建用户修改密码删除用户权限授权回收权限 视图 视图就是相当于创建一个表&#xff0c;将查询到的结果集给存储起来。像使用复杂的多表查询查询到的结果集就不可以对结果集操作。而…...

Linux基础(五):linux文件种类与扩展名

1.文件种类 文件种类含义正规文件&#xff08; regular file &#xff09;就是一般我们在进行存取的类型的文件&#xff0c; 在由 ls -al 所显示出来的属性方面&#xff0c; 第一个字符为 [ - ]&#xff0c; 例如 [-rwxrwxrwx ]。 另外&#xff0c; 依照文件的内容&#xff0c…...

C语言-c语言组成

1.C语言的组成 一个C源程序是由 一个或者多个.c文件 和 0个或者多个.h 文件 组成 源程序: 是指未编译的 按照一定的程序设计语言规范书写的文本文件 .c文件 : c源代码 .h文件 : 头文件(接口文件) 2. .c文件 1)预处理命令 以#开头的行,在编译之前 会事…...

编程题 7-13 日K蜡烛图【PAT】

文章目录 题目输入格式输出格式输入样例1输出样例1输入样例2输出样例2输入样例3输出样例3 题解解题思路完整代码 编程练习题目集目录 题目 股票价格涨跌趋势&#xff0c;常用蜡烛图技术中的 K K K 线图来表示&#xff0c;分为按日的日 K K K 线、按周的周 K K K 线、按月的…...

iOS开发工程师面试

iOS开发工程师面试题可以涵盖多个方面,包括但不限于iOS开发的基础知识、高级概念、性能优化、架构设计、最新技术等。 1. 基础知识 1.1 请解释iOS中的Xcode是什么,以及它在开发中的作用和功能有哪些? Xcode是用于iOS和macOS等苹果平台开发的集成开发环境(IDE),提供了代…...

无人机避障—— 激光雷达定高北醒TF03-UART(二)

无人机避障过程&#xff0c;光靠大疆飞控内部的气压计不准&#xff0c;很容易在高度较低的时候受到地面植被等障碍物影响&#xff0c;使得掉高严重&#xff0c;因此采用激光雷达定高模块进行定高。 硬件&#xff1a; 北醒TF03-UART、Xavier-NX 软件代码&#xff1a; 北醒官…...

在虚幻引擎中实现Camera Shake 相机抖动/震屏效果

在虚幻引擎游戏中创建相机抖动有时能让画面更加高级 , 比如 遇到大型的Boss , 出现一些炫酷的特效 加一些短而快的 Camera Shake 能达到很好的效果 , 为玩家提供沉浸感 创建Camera Shake 调整Shake参数 到第三人称或第一人称蓝图 调用Camera Shake Radius值越大 晃动越强...

SQL Server的文本和图像函数

新书速览|SQL Server 2022从入门到精通&#xff1a;视频教学超值版_sql server 2022 出版社-CSDN博客 《SQL Server 2022从入门到精通&#xff08;视频教学超值版&#xff09;&#xff08;数据库技术丛书&#xff09;》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) SQL Se…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

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…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...