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

Netty入门指南之NIO 网络编程

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

文章目录

  • 参考文献
  • 前言
  • 基础扫盲
    • 问题所在
  • 调整非阻塞
  • 技巧
  • 总结

参考文献

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

前言

在前面的文章中,我们详细学习并使用了NIO中的Channel和Buffer。然而,我们的示例中Channel的两端都是文件,我们一直使用的是FileChannel,没有与网络通信结合起来。从今天开始,我们将进入网络编程领域,使用NIO中的SocketChannelServerSocketChannel,为后续的Netty学习打下坚实的基础。

基础扫盲

由于我们现在的开发都是使用的SpringBoot,底层的网络通信都被Tomcat、Jetty等所处理,我们很少能够接触Socket套接字编程,这一个段落就来个基础性知识的扫盲。我们的客户端与服务端之间是使用Socket进行通信的,Socket是计算机网络中的传输层的内容,和TCP与UDP挂钩。在服务端有一个东西叫做ServerSocket,它是用来接收客户端请求,然后和客户端建立Socket连接的。下面的演示案例中,我写了一个服务端和客户端的案例。

服务端就是创建ServerSocketChannel,绑定端口启动,监听请求获取对应的SocketChannel
客户端就是去连接服务端所在机器的对应端口,发送数据相应数据即可
注意:

  • 服务端有两次阻塞,第一次阻塞是接收请求的时候,第二次阻塞是建立后连接等待接收数据的时候。说明NIO是有阻塞的,后面会写案例解决阻塞的
  • 端口,是应用进程启动后在传输层给其分配的,客户端是一个进程,服务端是一个进程。有了端口号两个进程就可以跨进程互相访问
  • 当服务端启动,就是一个主线程,接收请求和数据处理都是由主线程挨个处理,只要SocketChannel一经建立,服务端或者客户端不主动销毁就会一直在,但其中会不会有数据是两码子事
public class MyServer {public static void main(String[] args) throws Exception{// 1、创建ServerSocketChannelServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 2、设置服务端的监听端口serverSocketChannel.bind(new InetSocketAddress(8000));List<SocketChannel> channelList = new ArrayList<>();ByteBuffer buffer = ByteBuffer.allocate(20);// 3、接受客户端的连接,让它一直转(我们不知道啥时候会接收到请求)while (true) {// 4、SocketChannel代表服务端与Client链接的一个通道System.out.println("等待连接服务器...");// 发生阻塞,服务端在等待客户端的请求,接收到才会放行SocketChannel socketChannel = serverSocketChannel.accept();System.out.println("服务器已连接..." + socketChannel);// 4-1、接受一个客户端就存一个channelList.add(socketChannel);// 5、client与服务端 通信 NIOfor (SocketChannel channel : channelList) {System.out.println("开始实际的数据通信...");// 此处阻塞,对于的IO通信的阻塞,将channel中的数据读取到buffer中channel.read(buffer);// 开启读模式buffer.flip();CharBuffer result = StandardCharsets.UTF_8.decode(buffer);System.out.println("result = " + result);// 读完后开启写模式buffer.clear();System.out.println("实际的通信已经结束...");}}}
}
public class MyClient {public static void main(String[] args) throws Exception{// 1、创建客户端channel,并连接8000端口服务端SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress(8000));// 2、向服务端发送数据socketChannel.write(Charset.defaultCharset().encode("你好,我是Aomsir\n"));System.out.println("-------------------------------------");}
}

问题所在

在上面的案例中,服务端程序会面临两次阻塞。首先,在接收连接请求时,服务端程序需要等待新的连接请求。其次,一旦建立连接后,服务端可能需要等待客户端发送数据。这可能会导致一些问题:

  1. 单客户端多次请求问题: 如果今天只有一个客户端请求,按照上面的案例代码我们知道服务端在处理完这个客户端的请求后双方都没有选择断开Channel,那客户端第一次给服务端发送完数据后就会回到循环的开始一直阻塞新的连接请求到来,而不会去执行下面的IO处理,导致第一个客户端的后续请求得不到处理。这是当前单线程服务端模型的局限性,只有在接受新连接后才能处理请求。 这是由于ServerSocketChannel等待客户端请求时的阻塞
  2. 客户端保持连接问题: 第一个客户端发送完数据后没有断开与服务端的连接,服务端channelList中第一个Channel永远是第一个客户端的,服务端会一直等待来自该客户端的数据,但是第一个客户端已经没有数据发送了,这会导致服务端阻塞无法处理其他连接,因为它会一直在等待当前连接上的数据。这是由于SocketChannel处理IO数据时的阻塞。这需要特别处理的情况,通常可以通过设置超时或实现多线程来解决。

调整非阻塞

在上面的代码中,我们使用了标准的NIO编程方法,但同时又称它为非阻塞编程。然而,在代码中的两次阻塞操作似乎没有展现出非阻塞的特性,这是因为我们还未进行必要的设置。通过对ServerSocketChannel和SocketChannel的配置,我们可以将它们转换为非阻塞模式。只需执行以下两行代码:serverSocketChannel.configureBlocking(false);socketChannel.configureBlocking(false);

一旦这些设置生效,之前阻塞的客户端请求接收和IO处理不再会阻塞整个程序。当没有客户端请求或没有进行IO请求时,从ServerSocketChannel获取的SocketChannel将为null,从SocketChannel中读取的字节数将为0。为了进一步说明这一点,以下是示例代码:

public class MyServer1 {public static void main(String[] args) throws Exception{ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 设置serverSocketChannel为非阻塞,解决连接阻塞serverSocketChannel.configureBlocking(false);serverSocketChannel.bind(new InetSocketAddress(8000));List<SocketChannel> channelList = new ArrayList<>();ByteBuffer buffer = ByteBuffer.allocate(20);while (true) {// 此处等待请求不会阻塞,如果此时没有客户端连接进来,会返回nullSocketChannel socketChannel = serverSocketChannel.accept();// 4、如果接收到的socketChannel不为null,则将其添加到channelList中if (socketChannel != null) {// 设置socketChannel为非阻塞,解决数据读取阻塞socketChannel.configureBlocking(false);channelList.add(socketChannel);}// 5、客户端与服务端 通信 NIOfor (SocketChannel channel : channelList) {// 此处从channel中读取数据到buffer中会阻塞int read = channel.read(buffer);if (read > 0) {System.out.println("开始实际的数据通信...");buffer.flip();  // 开启读模式CharBuffer result = StandardCharsets.UTF_8.decode(buffer);System.out.println("result = " + result);buffer.clear();  // 开启写模式System.out.println("实际的通信已经结束...");}}}}
}

技巧

对于一个Java类,比如我们的客户端,我们可能需要在IDEA中运行多个。但是默认情况下我们在IDEA里面将客户端启动以后,它处于一直运行的状态,如果我这个时候再去点击运行,那就会将这个客户端重新运行,而不是启动一个新的进程,我们可以按照下面的方式进行设置。

  1. 打开IntelliJ IDEA,并确保你的项目已经打开。
  2. 在IDEA的顶部菜单栏中,点击 “Run”(运行)。
  3. 选择 “Edit Configurations”(编辑配置)。
  4. 在左侧窗格中,点击加号(+)以创建一个新的运行配置。
  5. 选择 “Application”(应用程序)作为配置类型。
  6. 在 “Name”(名称)字段中,为你的运行配置命名,例如 “Client1”。
  7. 在 “Main class”(主类)字段中,指定你想要运行的Java客户端的主类。
  8. 在 “Program arguments”(程序参数)字段中,如果有需要的话,添加客户端程序的参数。
  9. 在 “Working directory”(工作目录)字段中,指定客户端应运行的工作目录。
  10. 点击 “OK” 以保存该运行配置。
  11. 重复上述步骤,创建其他客户端的运行配置,每个配置使用不同的名称,主类和参数。
  12. 现在,你可以通过选择不同的运行配置来启动不同的客户端。在顶部工具栏 中,选择你想要运行的配置,然后点击运行按钮(绿色的播放按钮)。
    在这里插入图片描述

总结

在今天的文章中,我们将深入探讨SocketChannel和ServerSocketChannel,这两个在网络通信中起着关键作用的组件。我们将揭开网络通信中服务端的两次阻塞现象的神秘面纱,并详细介绍NIO如何有效地处理非阻塞。让我们一起扫除对这些概念的盲点,深入理解网络通信的内在机制。

相关文章:

Netty入门指南之NIO 网络编程

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Netty应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言基础扫…...

LeetCode(6)轮转数组【数组/字符串】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 189. 轮转数组 1.题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1…...

华为云Ascend310服务器使用

使用华为云服务器 cpu: 16vCPUs Kunpeng 920 内存&#xff1a;16GiB gpu&#xff1a;4* HUAWEI Ascend 310 cann: 20.1.rc1 操作系统&#xff1a;Ubuntu aarch64目的 使用该服务器进行docker镜像编译&#xff0c;测试模型。 已知生产环境&#xff1a;mindx版本为3.0.rc3&a…...

【poi导出excel模板——通过建造者模式+策略模式+函数式接口实现】

poi导出excel模板——通过建造者模式策略模式函数式接口实现 poi导出excel示例优化思路代码实现补充建造者模式策略模式 poi导出excel示例 首先我们现看一下poi如何导出excel&#xff0c;这里举个例子&#xff1a;目前想要导出一个Map<sex,List>信息&#xff0c;sex作为…...

自适应模糊PID控制器在热交换器温度控制中的应用

热交换器是一种常见的热能传递设备&#xff0c;广泛应用于各个工业领域。对热交换器温度进行有效控制具有重要意义&#xff0c;可以提高能源利用效率和产品质量。然而&#xff0c;受到热传导特性和外部环境变化等因素的影响&#xff0c;热交换器温度控制难度较大。本文提出一种…...

【系统救援】 Ubuntu重启失败,报错:UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY

问题定位及处理 查看错误信息&#xff1a;/dev/sda3 contains a file system with errors, check forced. /dev/sda3: Inodes that were part of a corrupted orphan linked list found. /dev/sda3: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. (i.e., without -a or -p o…...

【数据结构】树与二叉树(八):二叉树的中序遍历(非递归算法NIO)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…...

第九章 排序【数据结构】【精致版】

第九章 排序【数据结构】【精致版】 前言版权第九章 排序9.1 概述9.2 插入类排序9.2.1 直接插入排序**1-直接插入排序.c** 9.2.2 折半插入排序**2-折半插入排序.c** 9.2.3 希尔排序 9.3 交换类排序9.3.1冒泡排序**4-冒泡排序.c** 9.3.2 快速排序**5-快速排序.c** 9.4 选择类排…...

基于element-plus定义表格行内编辑配置化

文章目录 前言一、新增table组件二、使用步骤 前言 在 基于element-plus定义表单配置化 基础上&#xff0c;封装个Element-plus的table表格 由于表格不同于form组件&#xff0c;需自定义校验器&#xff0c;以下组件配置了单个校验&#xff0c;及提交统一校验方法&#xff0c;且…...

WebGL-Vue3-TS-Threejs:基础练习 / Javascript 3D library / demo

一、理解Three.js Three.js是一个用于WebGL渲染的JavaScript库。它提供了一组工具和类&#xff0c;用于创建和渲染3D图形和动画。简单理解&#xff08;并不十分准确&#xff09;&#xff0c;Three.js之于WebGL&#xff0c;好比&#xff0c;jQuery.js之于JavaScript。 OpenGL …...

2022年12月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 有n个按名称排序的商品,使用对分查找法搜索任何一商品,最多查找次数为5次,则n的值可能为?()(2分) A.5 B.15 C.30 D.35 答案:C 答案解析:对分查找最多查找次数m与个数之间n的…...

确定性 vs 非确定性:GPT 时代的新编程范式

分享嘉宾 | 王咏刚 责编 | 梦依丹 出品 | 《新程序员》编辑部 在 ChatGPT 所引爆的新一轮编程革命中&#xff0c;自然语言取代编程语言&#xff0c;在只需编写提示词/拍照就能出程序的时代&#xff0c;未来程序员真的会被简化为提示词的编写员吗&#xff1f;通过提示词操纵 …...

【Linux奇遇记】我和Linux的初次相遇

&#x1f308;个人主页: Aileen_0v0 &#x1f525;系列专栏:Linux奇遇记系列专栏&#x1f4ab;"没有罗马,那就自己创造罗马~" 目录 前端和后端的介绍 1.前端 2.后端 3.前后端区别 Linux在前后端开发中的角色 如何学习Linux 去进行程序开发 Linux的常见根目…...

剪贴板劫持--PasteJacker的使用

启动 PasteJacker [1] Windows [2] Linux [3] Exit第一次是让我们选择要攻击针对的目标系统&#xff0c;这里以Windows系统为例&#xff0c;即我自己的物理机 因此键入 1 &#xff0c;回车 [1] Download and execute a msfvenom backdoor using certutil (Web delivery Past…...

说一下vue2的响应式原理?

vue2采用数据代理数据劫持发布订阅模式的方法。 在初始化vue实例时&#xff0c;会把data对象和data对象的属性都添加到vm对象中&#xff0c;通过object.defineProperty()进行数据代理&#xff0c;用vm对象的属性来代理data对象的属性&#xff0c;并在Observer类中递归遍历data…...

如何使用CORS和CSP保护前端应用程序安全

前端应用在提供无缝用户体验方面起着核心作用。在当今互联网的环境中&#xff0c;第三方集成和API的普及使得确保强大的安全性至关重要。安全漏洞可能导致数据盗窃、未经授权访问以及品牌声誉受损。本文将向您展示如何使用CORS和CSP为您的网页增加安全性。 嗨&#xff0c;大家好…...

C/C++输出硬币翻转 2021年6月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C硬币翻转 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 C/C硬币翻转 2021年6月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 假设有N个硬币(N为不大于5000的正整数)&#xff0c;从1…...

ipad可能会在iOS 16中失去智能家居中心功能

在iOS 16测试版代码中发现的文本表明苹果将放弃对iPad家庭中心的支持 家庭app迎来重大改版&#xff0c;未来更将对智能家居互联互通标准Matter提供支持。 即使某一款智能家居设备再优秀&#xff0c;只要它没有接入HomeKit&#xff0c;那么就不能在苹果的家庭app中直接管理控制。…...

maven打包可运行jar

普通java程序 <build><finalName>JavaDeviceClient</finalName><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.8</source><…...

Arcgis连接Postgis数据库(Postgre入门十)

效果 步骤 1、矢量数据首先有在postgis数据库中 这个postgis数据库中的一个空间数据&#xff0c;数据库名称是test3&#xff0c;数据表名称是test 2、Arcgis中连接postgis数据库中 3、成功连接 可以将数据拷贝或导入到gdb数据库中...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...