当前位置: 首页 > 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数据库中...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...