做一组静态页面网站多少钱/外贸网站模板
目录
一、Hello World
1. 目标
2. 服务器端
3. 客户端
4. 流程梳理
💡 提示
5. 运行结果截图
二、Netty执行流程
1. 流程分析
2. 代码案例
2.1. 引入依赖
2.2. 服务端
服务端
服务端处理器
2.3. 客户端
客户端
客户端处理器
2.4. 代码截图
一、Hello World
1. 目标
开发一个简单的服务器端和客户端
- 客户端向服务器端发送 hello, world
- 服务器仅接收,不返回
加入依赖
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.39.Final</version>
</dependency>
2. 服务器端
new ServerBootstrap().group(new NioEventLoopGroup()) // 1 .channel(NioServerSocketChannel.class) // 2.childHandler(new ChannelInitializer<NioSocketChannel>() { // 3protected void initChannel(NioSocketChannel ch) {ch.pipeline().addLast(new StringDecoder()); // 5ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() { // 6@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {System.out.println(msg);}});}}).bind(8080); // 4
代码解读
- 1 处,创建 NioEventLoopGroup,可以简单理解为 线程池 + Selector 后面会详细展开
- 2 处,选择服务 Scoket 实现类,其中 NioServerSocketChannel 表示基于 NIO 的服务器端实现,其它实现
还有
- 3 处,为啥方法叫 childHandler,是接下来添加的处理器都是给 SocketChannel 用的,而不是给
ServerSocketChannel。
ChannelInitializer 处理器(仅执行一次),它的作用是待客户端 SocketChannel 建立连接后,执行
initChannel 以便添加更多的处理器
- 4 处,ServerSocketChannel 绑定的监听端口
- 5 处,SocketChannel 的处理器,解码 ByteBuf => String
- 6 处,SocketChannel 的业务处理器,使用上一个处理器的处理结果
3. 客户端
new Bootstrap().group(new NioEventLoopGroup()) // 1.channel(NioSocketChannel.class) // 2.handler(new ChannelInitializer<Channel>() { // 3@Overrideprotected void initChannel(Channel ch) {ch.pipeline().addLast(new StringEncoder()); // 8}}).connect("127.0.0.1", 8080) // 4.sync() // 5.channel() // 6.writeAndFlush(new Date() + ": hello world!"); // 7
代码解读
- 1 处,创建 NioEventLoopGroup,同 Server
- 2 处,选择客户 Socket 实现类,NioSocketChannel 表示基于 NIO 的客户端实现,其它实现还有
- 3 处,添加 SocketChannel 的处理器,ChannelInitializer 处理器(仅执行一次),它的作用是待客户端
SocketChannel 建立连接后,执行 initChannel 以便添加更多的处理器
- 4 处,指定要连接的服务器和端口
- 5 处,Netty 中很多方法都是异步的,如 connect,这时需要使用 sync 方法等待 connect 建立连接完毕
- 6 处,获取 channel 对象,它即为通道抽象,可以进行数据读写操作
- 7 处,写入消息并清空缓冲区
- 8 处,消息会经过通道 handler 处理,这里是将 String => ByteBuf 发出
- 数据经过网络传输,到达服务器端,服务器端 5 和 6 处的 handler 先后被触发,走完一个流程
4. 流程梳理
💡 提示
一开始需要树立正确的观念
- 把 channel 理解为数据的通道
- 把 msg 理解为流动的数据,最开始输入是 ByteBuf,但经过 pipeline 的加工,会变成其它类型对象,最后
输出又变成 ByteBuf
- 把 handler 理解为数据的处理工序
-
- 工序有多道,合在一起就是 pipeline,pipeline 负责发布事件(读、读取完成...)传播给每个
handler, handler 对自己感兴趣的事件进行处理(重写了相应事件处理方法)
-
- handler 分 Inbound 和 Outbound 两类
- 把 EeventLoop 理解为处理数据的工人
-
- 工人可以管理多个 channel 的 io 操作,并且一旦工人负责了某个 channel,就要负责到底(绑定)
- 工人既可以执行 io 操作,也可以进行任务处理,每位工人有任务队列,队列里可以堆放多个 channel
的待处理任务,任务分为普通任务、定时任务
-
- 工人按照 pipeline 顺序,依次按照 handler 的规划(代码)处理数据,可以为每道工序指定不同的工
人
5. 运行结果截图
二、Netty执行流程
1. 流程分析
- Netty 抽象出两组线程池BossGroup专门负责接收客户端的连接, WorkerGroup专门负责网络的读写
- BossGroup和WorkerGroup类型都是NioEventLoopGroup
- NioEventLoopGroup相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环是
NioEventLoop
- NioEventLoop表示一个不断循环的执行处理任务的线程,每个NioEventLoop都有一个 selector ,
用于监听绑定在其上的 socket 的网络通讯 用于监听绑定在其上的 socket 的网络通讯
- NioEventLoopGroup可以有多个线程,即可以含有多个NioEventLoop
- 每个BossNioEventLoop 循环执行的步骤有3步轮询 accept事件,处理 accept事件, 与client建立连
接 , 生成 NioSocketChannel ,并将其注册到某 个worker 的NIOEventLoop上的selector处理任务队
列的任务,即runAllTasks
- 每个Worker NIOEventLoop循环执行的步骤
轮询 read, write 事件,处理 i/o 事件,即read , write事件,在对应 NioSocketChannel处理,处理
任务队列的任务 ,即runAllTasks
- 每个Worker 的NIOEventLoop处理业务时,会使用 pipeline(管道), pipeline中包含了channel ,
即通过 pipeline可以获取到对应通道, 管道中维护了很多的处理器
2. 代码案例
2.1. 引入依赖
<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.19.1</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.42.Final</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.6.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.6.1</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies>
2.2. 服务端
服务端
public class NettyServer {public static void main(String[] args) {//创建bossgroupEventLoopGroup bossGroup = new NioEventLoopGroup();//创建workerGroupEventLoopGroup workerGroup = new NioEventLoopGroup();try {//创建服务器启动对象ServerBootstrap bootstrap = new ServerBootstrap();//设置启动的数学bootstrap.group(bossGroup, workerGroup)//设置老板组合工作组.channel(NioServerSocketChannel.class)//设置通道类型.option(ChannelOption.SO_BACKLOG, 128)//设置线程队列的连接数.childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态//设置工作组的通道初始化,设置处理器的管道线.childHandler(new ChannelInitializer<SocketChannel>() {//初始化通道的方法protected void initChannel(SocketChannel channel) throws Exception {System.out.println("客户端 socketChannel 初始化" + channel);//处理器管道线中添加处理器channel.pipeline().addLast(new NettyServerHandler());}});System.out.println("服务器启动...");//绑定服务端口,返回异步通道返回对象ChannelFuture channelFuture = bootstrap.bind(6668).sync();//添加监听channelFuture.addListener(new ChannelFutureListener() {//监听操作完成public void operationComplete(ChannelFuture channelFuture) throws Exception {if (channelFuture.isSuccess()) {System.out.println("监听端口6668成功");} else {System.out.println("监听端口6668失败");}}});//设置异步通道关闭事件channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
服务端处理器
public class NettyServerHandler extends ChannelInboundHandlerAdapter{/**读事件,客户端发送数据会触发该方法1. ChannelHandlerContext ctx:上下文对象, 含有 管道pipeline , 通道channel, 地址2. Object msg: 就是客户端发送的数据 默认Object*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {Channel channel = ctx.channel();System.out.println("服务器读取线程 "+Thread.currentThread().getName()+" channel="+channel);System.out.println("server ctx="+ctx);ByteBuf buf = (ByteBuf) msg;System.out.println("客户端发送消息是:"+buf.toString(CharsetUtil.UTF_8));System.out.println("客户端地址:"+channel.remoteAddress());}/**读完毕触发*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {//写并且清缓冲区,一般讲,我们对这个发送的数据进行编码ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端", CharsetUtil.UTF_8));}/*处理异常, 一般是需要关闭通道*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}
2.3. 客户端
客户端
public class NettyClient {public static void main(String[] args) {//创建事件循环组EventLoopGroup group = new NioEventLoopGroup();try {//重建客户端启动类Bootstrap bootstrap = new Bootstrap();bootstrap.group(group)//设置循环组.channel(NioSocketChannel.class)//设置通道//设置通道初始化.handler(new ChannelInitializer<SocketChannel>() {//初始化通道protected void initChannel(SocketChannel channel) throws Exception {//设置管道线上的处理器channel.pipeline().addLast(new NettyClientHandler());}});System.out.println("客户端 ok");//请求连接,返回异步结果对象ChannelFuture future = bootstrap.connect("127.0.0.1", 6668).sync();//设置异步通道关闭事件future.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();}finally {group.shutdownGracefully();}}
}
客户端处理器
public class NettyClientHandler extends ChannelInboundHandlerAdapter {/*通道就绪就会触发该方法*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("client:" +ctx);ctx.writeAndFlush(Unpooled.copiedBuffer("hello server", CharsetUtil.UTF_8));}/*通道内有读取事件时候触发*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf) msg;System.out.println("服务器回复的消息:"+buf.toString(CharsetUtil.UTF_8));System.out.println("服务器地址:"+ctx.channel().remoteAddress());}/*异常*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
2.4. 代码截图
相关文章:

Netty篇(入门编程)
目录 一、Hello World 1. 目标 2. 服务器端 3. 客户端 4. 流程梳理 💡 提示 5. 运行结果截图 二、Netty执行流程 1. 流程分析 2. 代码案例 2.1. 引入依赖 2.2. 服务端 服务端 服务端处理器 2.3. 客户端 客户端 客户端处理器 2.4. 代码截图 一、Hel…...

【渗透测试】payload记录
Java开发使用char[]代替String保存敏感数据 Java Jvm会提供内存转储功能,当Java程序dump后,会生成堆内存的快照,保存在.hprof后缀的文件中,进而导致敏感信息的泄露。char[]可以在存储敏感数据后手动清零,String对象会…...

2024自动驾驶线控底盘行业研究报告
自动驾驶线控底盘是实现自动驾驶的关键技术之一,它通过电子信号来控制车辆的行驶,包括转向、制动、驱动、换挡和悬架等系统。线控底盘技术的发展对于自动驾驶汽车的实现至关重要,因为它提供了快速响应和精确控制的能力,这是自动驾驶系统所必需的。 线控底盘由五大系统组成…...

css3D变换用法
文章目录 CSS3D变换详解及代码案例一、CSS3D变换的基本概念二、3D变换的开启与景深设置三、代码案例 CSS3D变换详解及代码案例 CSS3D变换是CSS3中引入的一种强大功能,它允许开发者在网页上创建三维空间中的动画和交互效果。通过CSS3D变换,你可以实现元素…...

Rust:启动与关闭线程
在 Rust 编程中,启动和关闭线程是并发编程的重要部分。Rust 提供了强大的线程支持,允许你轻松地创建和管理线程。下面将详细解释如何在 Rust 中启动和关闭线程。 启动线程 在 Rust 中,你可以使用标准库中的 std::thread 模块来创建和启动新…...

Ubuntu 的 ROS 2 操作系统安装与测试
引言 机器人操作系统(ROS, Robot Operating System)是一种广泛应用于机器人开发的开源框架,提供了丰富的库和工具,支持开发者快速构建、控制机器人并实现智能功能。 当前,ROS 2 的最新长期支持版本为 Humble Hawksbil…...

在双显示器环境中利用Sunshine与Moonlight实现游戏串流的同时与电脑其他任务互不干扰
我和老婆经常会同时需要操作家里的电脑,在周末老婆有时要用电脑加班上网办公,而我想在难得的周末好好地Game一下(在客厅用电视机或者平板串流),但是电脑只有一个,以往我一直都是把电脑让给老婆,…...

ElasticSearch备考 -- Cross cluster replication(CCR)
一、题目 操作在cluster1(local)中操作索引task,复制到cluster2(remote)中 二、思考 CCR 我们可以对标MySQL 理解为为主从,后者备份。主节点负责写入数据,从/备节点负责同步时主节点的数据。 …...

windows C#-异常处理
C# 程序员使用 try 块来对可能受异常影响的代码进行分区。 关联的 catch 块用于处理生成的任何异常。 finally 块包含无论 try 块中是否引发异常都会运行的代码,如发布 try 块中分配的资源。 try 块需要一个或多个关联的 catch 块或一个 finally 块,或两…...

边缘计算在智能制造中的应用
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 边缘计算在智能制造中的应用 边缘计算在智能制造中的应用 边缘计算在智能制造中的应用 引言 边缘计算概述 定义与原理 发展历程 …...

点云开发:从入门到精通的全面教程
简介 点云技术已成为计算机视觉、自动驾驶、3D重建等领域的重要组成部分。本教程旨在引导你从零基础开始学习点云开发,深入理解其背后的数学原理,并提供实用的开发技巧。 章节目录 点云技术概述 点云的定义及应用场景点云数据的来源和采集工具点云数据…...

【含文档】基于ssm+jsp的商店会员系统(含源码+数据库+lw)
1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: apache tomcat 主要技术: Java,Spring,SpringMvc,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定义了两个…...

【大数据学习 | kafka高级部分】文件清除原理
2. 两种文件清除策略 kafka数据并不是为了做大量存储使用的,主要的功能是在流式计算中进行数据的流转,所以kafka中的数据并不做长期存储,默认存储时间为7天 那么问题来了,kafka中的数据是如何进行删除的呢? 在Kafka…...

dolphin 配置data 从文件导入hive 实践(一)
datax 支持多种数据源的相互读写,作为开源软件,提供了离线采集功能,方便系统开发,过程中遇到诸多配置,需要开发者自己探索,免费同样有成本 配置模板 {"setting": {},"job": {"s…...

Docker Compose部署Rabbitmq(脚本下载延迟插件)
整个工具的代码都在Gitee或者Github地址内 gitee:solomon-parent: 这个项目主要是总结了工作上遇到的问题以及学习一些框架用于整合例如:rabbitMq、reids、Mqtt、S3协议的文件服务器、mongodb github:GitHub - ZeroNing/solomon-parent: 这个项目主要是…...

麦当劳自助点餐机——实现
餐厅自助点餐优点 1. 降低服务成本: - 减少了对服务员数量的需求,降低了人力成本。 - 减轻了服务员的工作负担,使其能够更专注于提供优质的服务,如解决顾客的特殊需求和处理复杂问题。 2. 提升点餐效率和准确性…...

C++ STL CookBook 6:STL Containers (I)
目录 顺序容器 关联容器 容器适配器 使用统一擦除函数从容器中删除指定项 在恒定时间内对一个对排序不敏感的vector中删除项目 如果不确定自己访问容器会不会越界,那就使用.at方法而不是[] 在我们开始之前,先来回顾一下传统的经典的几个容器&#…...

行转列实现方式总结
前言 在日常开发中遇到了,需要对表中数据某个字段行数据转成列,个人觉得这中做目前想到两种, 一种是sql 操作, 另一种代码中做逻辑处理。 方式一 Java 操作 import lombok.Data;import java.util.ArrayList; import java.util.H…...

【go从零单排】初探goroutine
🌈Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 📗概念 Goroutines 是 Go 语言中的一种轻量级线程,用于并发编程。它们允许程…...

HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)本地搜索接入方案
一、方案概述 当用户使用应用/元服务时,开发者可以按照标准意图Schema向系统共享数据,并支持意图调用(空调用与传参调用),以实现用户点击卡片后,可后台执行功能(例如播放指定歌曲)或…...

C语言可变参数列表编程实战指南:从基础概念到高级应用的全面解析
引言 在C语言中,可变参数列表的功能使得函数能够灵活地处理不确定数量的输入参数。本文将深入探讨可变参数列表的基础概念、技术原理及其在实际编程中的应用,帮助开发者更好地理解和使用这一特性。 一、可变参数列表的基本概念 1.1 什么是可变参数列表…...

AndroidStudio-文本显示
一、设置文本的内容 1.方式: (1)在XML文件中通过属性:android:text设置文本 例如: <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.andr…...

HBuilderX运行微信小程序,编译的文件在哪,怎么运行
1. 点击HBuilderX顶部的运行-运行到小程序模拟器-微信开发者工具,就会开始编译 2. 编译完成后的文件在根目录找到 unpackage -- dist -- dev -- mp-weixin, 这里面就是编译后的文件,如果未跳转到开发者工具,那可能是没设置启动路径࿰…...

百亿AI数字人社会初现:Project Sid展示智能代理文明进化路径
项目背景 Project Sid 是一项开创性的AI代理人文明实验,旨在通过新开发的认知架构 PIANO 探讨AI代理人是否能够在大规模数字社会中实现文明的演进。这项实验不仅展示了社会进步、角色分化、治理体系及文化传播等特征,还揭示了一个包含百亿“数字人类”的社会可能性。 PIANO…...

代码随想录训练营Day21 | 491.递增子序列 - 46.全排列 - 47.全排列 II - 332.重新安排行程 - 51.N皇后 - 37.解数独
491.递增子序列 题目链接:491.递增子序列思路:和子集那道题思路很像,每次在数组中选择一个数,选过的数不能选择,这里要求集合数量必须大于2个才能符合,仍然需要去重,但这里选额的是子序列&…...

多用户商城系统的功能及设计和开发
多用户商城系统的功能及设计与开发(基于 PHP MySQL) 在现代电子商务平台的开发中,PHP MySQL 是一对非常流行且高效的技术栈。PHP作为服务器端脚本语言,结合MySQL数据库,可以高效地处理多用户商城系统的各种需求。本…...

2024年11月8日day8
半加器和全加器的区别 半加器:只能处理两个二进制位的相加,无法处理进位。全加器:不仅能处理两个二进制位的相加,还能处理来自低位的进位。 ⑴ 完成满足754标准存储格式的浮点数((43940000)16的十进制数值)…...

Debezium系列之:Debezium3版本增量快照和只读增量快照应用的变化
Debezium系列之:Debezium3版本增量快照和只读增量快照应用的变化 一、需求背景二、基于数据库信号表使用增量快照案例三、基于Kafka信号Topic使用增量快照案例四、只读增量快照案例五、增量快照技术总结增量快照相关知识请阅读博主下面系列文章: Debezium系列之:实现增量快照…...

Python正则表达式1 re.match惰性匹配详解案例
点个关注 re.match() re.match() 函数尝试从字符串的开头开始匹配一个模式,如果匹配成功,返回一个匹配成功的对象,否则返回None。大小写区分,内容匹配不到后面的,只能匹配一个,不能有空格(开头匹配&#…...

WPF(C#)学习日志10:Prism框架下按键绑定
在Prism框架下,提供了DelegateCommand类用于处理了UI的按键请求,XAML中可以直接采用 Command"{Binding **}" 来绑定这些方法。这个类是一个泛型的类生命时仅需要DelegateCommand<T>即可,同时在XAML中绑定CommandParameter&qu…...