Netty入门指南之传统通信的问题

作者简介:☕️大家好,我是Aomsir,一个爱折腾的开发者!
个人主页:Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客
当前专栏:Netty应用专栏_Aomsir的博客-CSDN博客

文章目录

  • 参考文献
  • 前言
  • 多线程版
  • 线程池版
  • 总结

参考文献

  • 孙哥suns说Netty
  • Netty官方文档

前言

前一篇文章中,我学到了与Netty有关的基础知识,了解NIO这个非阻塞式IO,那今天我们来聊聊传统的网络通信开发方式以及它所存在的问题,也就是使用 Socket的方式。Socket是阻塞式的IO,我们要做通信肯定得涉及多线程或者线程池的方式,这两种方式对于Socket都不友好,都有问题,如下详细分析一下。

注意:由于我们平常开发都是面向Tomcat开发的,很少会有机会能够接触Socket编程

多线程版

下面是多线程版网络通信的情况。从图中可以明显看出,随着客户端请求服务端的增加,服务端为处理这些请求不断创建新线程,而这一过程缺乏充分的限制,会无节制的进行创建。每次虚拟机创建线程都需要与操作系统进行通信,这会耗费时间和占用内存,导致内存使用量不断上升。此外,当所创建的线程数量超过了CPU核心数时,CPU就不得不进行轮转处理,这将导致CPU占用率飙升。
在这里插入图片描述

public class AomsirServer {public static void main(String[] args) {ServerSocket serverSocket = null;try {serverSocket = new ServerSocket(8080);Socket socket = null;while (true) {socket = serverSocket.accept();new Thread(new AomsirServerHandler(socket)).start();}} catch (Exception e) {e.printStackTrace();} finally {if (serverSocket != null) {try {serverSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}/*** 用于处理通信请求的线程*/
class AomsirServerHandler implements Runnable {private Socket socket;public AomsirServerHandler(Socket socket) {this.socket = socket;}public void run() {BufferedReader bufferedReader = null;try {bufferedReader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));while (true) {String line = bufferedReader.readLine();if (line != null) {System.out.println("line = " + line);}}} catch (Exception e) {e.printStackTrace();} finally {if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
public class AomsirClient {public static void main(String[] args) {Socket socket = null;PrintWriter printWriter = null;try {socket = new Socket("127.0.0.1", 8080);printWriter = new PrintWriter(socket.getOutputStream());printWriter.write("send date to server ");printWriter.flush();} catch (Exception e) {e.printStackTrace();} finally {if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}if (printWriter != null) {printWriter.close();}}}
}

线程池版

在上述多线程版网络通信中,服务端以一种无限制的方式为每个请求创建新线程,这导致高并发下线程数量无限增加。为了解决这一问题,我们提出了一种解决方案,即使用线程池。这是一种基于池化思想的方法,通过在服务端启动时创建固定数量的线程(例如N个),来限制后续线程的创建。这N个线程将专用于后续请求的处理,不再创建新的线程。当一个请求完成处理后,线程将被放回线程池,以供后续请求使用。如果请求数量超过了线程池的线程数量,后续请求将进入队列等待。这一方法有效地解决了无节制创建线程的问题。

然而,尽管线程池解决了线程创建问题,它引入了新的潜在问题,即阻塞问题。举例来说,如果线程1分配给了客户端A,但客户端1在某一时刻发生阻塞,无法继续处理请求,线程1将不得不一直等待客户端A,无法返回线程池,导致服务端处理请求的效率降低。
在这里插入图片描述

public class AomsirServer1 {// 创建线程池private static ExecutorService executorService;// 初始化线程池static{executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),20,120L, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1000));}public static void main(String[] args) {ServerSocket serverSocket = null;try {serverSocket = new ServerSocket(8080);Socket socket = null;while (true) {socket = serverSocket.accept();//new Thread(new SunsServerHandler(socket)).start();//线程池executorService.execute(new AomsirServerHandler(socket));}} catch (Exception e) {e.printStackTrace();} finally {if (serverSocket != null) {try {serverSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}/*** 服务端处理客户端请求的线程*/
class AomsirServerHandler implements Runnable {private Socket socket;public AomsirServerHandler(Socket socket) {this.socket = socket;}public void run() {BufferedReader bufferedReader = null;try {bufferedReader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));while (true) {String line = bufferedReader.readLine();if (line != null) {System.out.println("line = " + line);}}} catch (Exception e) {e.printStackTrace();} finally {if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
public class AomsirClient1 {public static void main(String[] args) {Socket socket = null;PrintWriter printWriter = null;try {socket = new Socket("127.0.0.1", 8080);printWriter = new PrintWriter(socket.getOutputStream());printWriter.write("send date to server ");printWriter.flush();} catch (Exception e) {e.printStackTrace();} finally {if (socket != null) {try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}if (printWriter != null) {printWriter.close();}}}
}

总结

在客户端-服务器结构中,使用BIO(阻塞I/O)进行网络通信时,无论是无限制地创建线程,还是通过线程池限制线程创建,都难以避免一个共同的问题:当客户端连接到服务器后,在一段时间内不进行通信,线程将被空闲浪费,导致资源的低效利用。

为了解决这个问题,我们可以采用NIO(非阻塞I/O)来处理网络通信。NIO允许服务器同时管理多个连接,而不需要为每个连接创建一个单独的线程。这使得服务器能够更高效地处理大量连接,减少了资源浪费。Netty是一个常见的工具,它底层使用了NIO,为我们开发者提供了更容易使用和管理的方式来构建高性能的网络应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/132930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于APM(PIX)飞控和missionplanner制作遥控无人车-从零搭建自主pix无人车无人坦克

前面的步骤和无人机调试一样&#xff0c;可以参考无人机相关专栏。这里不再赘述。 1.安装完rover的固件后&#xff0c;链接gps并进行校准。旋转小车不同方向&#xff0c;完成校准&#xff0c;弹出成功窗口。 2.校准遥控器。 一定要确保遥控器模式准确&#xff0c;尤其是使用没…

轻量封装WebGPU渲染系统示例<20>- 美化一下元胞自动机(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/GameOfLifePretty.ts 系统特性: 1. 用户态与系统态隔离。 2. 高频调用与低频调用隔离。 3. 面向用户的易用性封装。 4. 渲染数据(内外部相关资源)和渲染机制分离…

redis-plus-plus访问REDIS集群

编程语言&#xff1a;C 开源库&#xff1a;redis-plus-plus 接口类&#xff1a;RedisCluster 初始化需要输入任意一个结点的IP和端口&#xff0c;如果设置了密码&#xff0c;还需要密码的明文并使用ConnectionOptions类。 初始化完成后可以直接进行读/写操作。 RedisClust…

网络唤醒(Wake-on-LAN, WOL)

远程唤醒最简单的方法&#xff1a;DDNSTOOpenwrt网络唤醒&#xff0c;完美实现。 原帖-远程唤醒_超详细windows设置远程唤醒wol远程连接&#xff08;远程开机&#xff09; WOL Web# 访问 Wake on Lan Over The Interweb by Depicus 可以无需借助软件很方便的从网页前端唤醒远…

使用Anaconda安装TensorFlow环境以及没有搜到的报错的解决方法

1.在官网下载Anaconda 这一步几乎不会有人报错 下稳定的版本 或者最新的版本都可以 2.TensorFlow分两个版本 一个是用cpu跑 另一个是用gpu跑 显而易见 cpu的计算性能已经比不上现在主流的显卡了 所以有独显的电脑尽量安装gpu版本 CPU版本: 先给出cpu版本的安装方法: 打开A…

描述低轨星座的特点和通信挑战,以及它们在5G和B5G中的作用。

文章目录 2章4 章5章&#xff08;没看&#xff09;6章&#xff08;没看&#xff09; 2章 将卫星星座中每个物理链路中可实现的数据速率、传播延迟和多普勒频移与3GPP技术报告中的参数进行分析和比较[3]。 相关配置 面向连接的网络&#xff0c;预先简历链路 卫星和地面终端有…

Unraid 无法远程访问 Web UI 的解决方法

在将 Unraid 系统升级到 6.12.1 版本之后&#xff0c;发现无法通过 ZeroTier 或蒲公英在外网访问 Unraid 的 Web 页面&#xff0c;但是直接访问 Docker 的端口可以正常访问。 初步判断&#xff0c;这很有可能是默认的 80 端口出现了问题。Unraid 的 Web 服务器默认监听 80 端口…

自动化测试--验证邮件内容

场景 业务上有许多发送邮件的场景&#xff0c;发送的邮件基本上都是自动发送的&#xff0c;而且邮件内容是很重要的&#xff0c;对于邮件发没发送&#xff0c;发送的时间点对不对每次回归测试工作量太大了&#xff0c;所以考虑把这部分内容加入到自动化测试中 工具 python g…

了解计算机的大小端存储模式

我们在计算机中存储数据时&#xff0c;数据是如何组织和表示的是一个重要的问题。其中一个关键概念是 大小端存储模式&#xff08;Endianness&#xff09;&#xff0c;它描述了多字节数据在内存中的存储方式。本文将介绍大小端存储模式的原理、应用和区别。 什么是大小端存储模…

通过全流量查看部门或客户端网络使用情况

近年来&#xff0c;随着数字化转型和云计算服务的广泛应用&#xff0c;组织和企业对于网络带宽和性能的需求也在不断增长。 网络的稳定性、性能和安全性对于业务流程的顺畅运行至关重要。因此&#xff0c;了解部门或客户端网络的使用情况是网络管理和优化的关键。本文将通过Ne…

Docker数据管理、网络与Cgroup资源限制

目录 一、Docker的数据管理 1、数据卷 2、数据卷容器 3、端口映射 4、容器互联 二、Docker网络 2.1Docker网络实现原理 2.2Docker 的网络模式 3.3网络模式详解&#xff1a; host模式 container模式 none模式 bridge模式 自定义网络 创建自定义网络 三、Cgroup资源…

Maven修改仓库和镜像地址

目录 1、修改仓库地址2、修改镜像地址 1、修改仓库地址 使用IDEA时,如果不指定自己下载的Maven,idea会默认使用自带的Maven 3&#xff08;bundle)。maven 3默认的仓库路径一般是在c盘的用户文件夹中的.m2目录下&#xff1a; 当maven下的pom文件中的依赖逐渐增加时,maven仓库下…

k8s报错pause 3.2 解决方案

报错 Failed to create pod sandbox: rpc error: code Unknown desc failed to get sandbox image "k8s.gcr.io/pause:3.2": failed to pull image "k8s.gcr.io/pause:3.2": failed to pull and unpack image "k8s.gcr.io/pause:3.2": failed…

Hook函数

在嵌入式系统中&#xff0c;hook函数&#xff08;也被称为钩子函数&#xff09;是一种特殊类型的函数&#xff0c;它会在特定的事件发生时被操作系统内部调用。例如&#xff0c;在实时操作系统&#xff08;RTOS&#xff09;中&#xff0c;如果删除了一个任务&#xff0c;就会调…

0基础学习VR全景平台篇第116篇:认识修图软件Photoshop

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 今天给大家讲解修图软件Photoshop&#xff0c;下面我们开始吧&#xff01; &#xff08;PS软件课程大纲&#xff09; 1.Photoshop是什么 发明人Adobe Photoshop&#xff0c;简称…

剑指Offer-推理二叉树

剑指Offer-推理二叉树 LCR 124. 推理二叉树 题目如下 某二叉树的先序遍历结果记录于整数数组 preorder&#xff0c;它的中序遍历结果记录于整数数组 inorder。请根据 preorder 和 inorder 的提示构造出这棵二叉树并返回其根节点。 注意&#xff1a;preorder 和 inorder 中均…

JavaScript作用域实战

● 首先&#xff0c;我们先创建一个函数&#xff0c;和以前一样&#xff0c;计算一个年龄的 function calcAge(birthYear) {const age 2037 - birthYear;return age; }● 然后我们创建一个全局变量&#xff0c;并调用这个函数 const firstName "IT知识一享"; cal…

Wordpress plugin removes ‘/category‘

plugin removes /category from your category permalinks Remove Category URL – WordPress plugin | WordPress.org

学习代码20231106

解释代码&#xff1a;os.environ[“OMP_NUM_THREADS“] “1“ 这行代码涉及到 Python 的 os 模块和环境变量。它的作用是设置名为 “OMPNUMTHREADS” 的环境变量的值为 “1”。让我解释一下各部分的含义&#xff1a; 1.os.environ: 这是 Python 中的一个字典&#xff0c;包含…

Thread类的基本操作(JAVA多线程)

线程是操作系统中的概念&#xff0c;操作系统内核实现了线程这样的机制&#xff0c;并提供了一些API供外部使用。 JAVA中 Thread类 将系统提供的API又近一步进行了抽象和封装&#xff0c;所以如果想要使用多线程就离不开 Thread 这个类。 线程的创建(Thread类) 在JAVA中 创建…