用netty实现zcool_Netty框架入门-程序员宅基地

技术标签: 用netty实现zcool  

一、概述

Netty是由JBOSS提供的一个java开源框架。

Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

二、体系结构图

三、Netty的核心结构

Netty是典型的Reactor模型结构,在实现上,Netty中的Boss类充当mainReactor,NioWorker类充当subReactor(默认NioWorker的个数是当前服务器的可用核数)。

在处理新来的请求时,NioWorker读完已收到的数据到ChannelBuffer中,之后触发ChannelPipeline中的ChannelHandler流。

Netty是事件驱动的,可以通过ChannelHandler链来控制执行流向。因为ChannelHandler链的执行过程是在subReactor中同步的,所以如果业务处理handler耗时长,将严重影响可支持的并发数。

四、客户端和服务器端通信Demo

Server-main:

ChannelFactory factory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());

ServerBootstrap bootstrap = new ServerBootstrap(factory);

bootstrap.setPipelineFactory(new ChannelPipelineFactory(){

@Override

public ChannelPipeline getPipeline() throws Exception {

return Channels.pipeline(new TimeServerHandler());

}

});

bootstrap.setOption("child.tcpNoDelay", true);

bootstrap.setOption("child.keepAlive", true);

bootstrap.bind(new InetSocketAddress(1989));

ChannelFactory 是一个创建和管理Channel通道及其相关资源的工厂接口,它处理所有的I/O请求并产生相应的I/O ChannelEvent通道事件。这个工厂并自己不负责创建I/O线程。应当在其构造器中指定该工厂使用的线程池,这样我们可以获得更高的控制力来管理应用环境中使用的线程。

ServerBootstrap 是一个设置服务的帮助类。设置了一个继承自ChannelPipelineFactory的匿名类,用来作为ChannelPipeline通道,当服务器接收到一个新的连接,一个新的ChannelPipeline管道对象将被创建,并且所有在这里添加的ChannelHandler对象将被添加至这个新的ChannelPipeline管道对象。

Server-Handler:

@Override

public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {

//TimeServer

Channel ch = e.getChannel();

ChannelBuffer time = ChannelBuffers.buffer(8);

time.writeLong(System.currentTimeMillis());

ChannelFuture future = ch.write(time);

future.addListener(new ChannelFutureListener() {

@Override

public void operationComplete(ChannelFuture arg0) throws Exception {

Channel ch = arg0.getChannel();

ch.close();

}

});

}

Handler中是我们的业务逻辑,在Server的Handler里重载了channelConnected方法,当收到连接请求时,将当前服务器时间写入到Channel,并且在写完后触发关闭Channel。

Client-main:

ChannelFactory factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());

ClientBootstrap bootstrap = new ClientBootstrap(factory);

bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

@Override

public ChannelPipeline getPipeline() throws Exception {

return Channels.pipeline(new TimeClientHandler());

}

});

bootstrap.setOption("tcpNoDelay",true);

bootstrap.setOption("keepAlive", true);

bootstrap.connect(new InetSocketAddress("127.0.0.1", 1989));

Client端初始化Netty的过程和Server类似,只是将使用到的类替换为Client端的。

Client-Handler:

@Override

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

ChannelBuffer buf = (ChannelBuffer)e.getMessage();

Long currentTimeMillis = buf.readLong();

System.out.println(new Date(currentTimeMillis));

e.getChannel().close();

}

Client端的Handler里,我们将从服务器端接收到的信息转换为时间打印到控制台。

五、基于HTTP协议的服务器端实现

//HttpServerPipelineFactory.java

public class HttpServerPipelineFactory implements ChannelPipelineFactory {

@Override

public ChannelPipeline getPipeline() throws Exception {

ChannelPipeline pipeline = Channels.pipeline();

pipeline.addLast("decoder", new HttpRequestDecoder());

pipeline.addLast("encoder", new HttpResponseEncoder());

pipeline.addLast("handler", new HttpServerHandler());

return pipeline;

}

}

新建一个HttpServerPipelineFactory类,在getPipeline()方法中添加了对Http协议的支持。

// HttpServer.java

bootstrap.setPipelineFactory(new HttpServerPipelineFactory());

在Server里面使用我们新建的HttpServerPipelineFactory。

//HttpServerHandler.java

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

DefaultHttpRequest defaultHttpRequest = (DefaultHttpRequest)e.getMessage();

String uri = defaultHttpRequest.getUri();

byte[] data = defaultHttpRequest.getContent().array();

String content = URLDecoder.decode(new String(data),"utf-8").trim();

System.out.println(uri+"|"+content);

Channel ch = e.getChannel();

HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);

ChannelBuffer buffer = new DynamicChannelBuffer(2048);

buffer.writeBytes("200".getBytes("UTF-8"));

response.setContent(buffer);

response.setHeader("Content-Type", "text/html;charset=UTF-8");

response.setHeader("Content-Length", response.getContent().writerIndex());

if (ch.isOpen() && ch.isWritable()) {

ChannelFuture future = ch.write(response);

future.addListener(new ChannelFutureListener() {

@Override

public void operationComplete(ChannelFuture arg0) throws Exception {

Channel ch = arg0.getChannel();

ch.close();

}

});

}

}

在Handler里面我们可以直接拿到DefaultHttpRequest类型的对象,因为Netty已经用HttpRequestDecoder帮我们把接受到的数据都转换为HttpRequest类型了。

使用了多个Handler后,通过下图,Netty的事件驱动就可以被很好的理解了:

UpstreamEvent是被UpstreamHandler们自底向上逐个处理,DownstreamEvent是被DownstreamHandler们自顶向下逐个处理,这里的上下关系就是向ChannelPipeline里添加Handler的先后顺序关系。

六、总结

Netty是一个简单却不失强大的架构。这个架构由三部分组成——缓冲(Buffer)、通道(Channel)、事件模型(Event Model)——所有的高级特性都构建在这三个核心组件之上。

七、深入学习

http://netty.io/

https://github.com/netty/netty

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39948442/article/details/111793849

智能推荐

第1篇 目标检测概述 —(2)目标检测算法介绍_检测类算法的作用-程序员宅基地

文章浏览阅读1.4k次,点赞3次,收藏8次。目标检测算法是一种计算机视觉算法,用于在图像或视频中识别和定位特定的目标物体。本节课就给大家重点介绍下基于深度学习的目标检测算法!_检测类算法的作用

Linux编译mplayer播放badapple及编译fbv加载图片(基于V3S预告板子要开源了)_v3s笔记-程序员宅基地

文章浏览阅读1.8k次,点赞3次,收藏15次。Linux编译mplayer播放badapple及编译fbv加载图片(基于V3S)1.编译前准备:1.linux5.10内核2.2018.02bulidroot3.v3s板子2.linux内核配置1.修改设备树(linux-5.10/arch/arm/boot/dts/文件夹下)1.修改sun8i-v3s.dtsi文件的最后一个dma的位置添加以下代码: codec_analog: codec-analog@01c23000 { compatible = "allwinner,sun_v3s笔记

我们应如何度过自己的大学生活?_如何度过大学生活1000字-程序员宅基地

文章浏览阅读3.1k次。我们应如何度过自己的大学生活?  踏着九月的烈日,我们成功地来到了河南理工大学,开始了我们的大学生活,那么你可曾想过,我们到底应该如何度过我们的大学生活才算有意义呢?  可曾记得高中老师说的最多的一句话:“好好学吧!上了大学就轻松了!”每当听到这句话时都会给我们莫大的鼓励,也让我们对大学充满了憧憬。那么大学生活真如高中老师说的那样轻松吗?其实不然!高中老师所谓的轻松只是在一定程度上正课的时..._如何度过大学生活1000字

python snownlp情感分析简易demo(分享),没有我Python干不成的事!_snowlp情感分析代码-程序员宅基地

文章浏览阅读745次。SnowNLP是国人开发的python类库,可以方便的处理中文文本内容,是受到了TextBlob的启发而写的,由于现在大部分的自然语言处理库基本都是针对英文的,于是写了一个方便处理中文的类库,并且和TextBlob不同的是,这里没有用NLTK,所有的算法都是自己实现的,并且自带了一些训练好的字典。注意本程序都是处理的unicode编码,所以使用时请自行decode成unicode。MIT许可下发行。其github主页可能有些不准确,我也是随便提取的数据,不过snownlp还是号称情感分析准确很高的!_snowlp情感分析代码

命令行安装todesk_todesk命令行csdn-程序员宅基地

文章浏览阅读653次,点赞10次,收藏7次。要想通过命令行安装todesk,也是比较简单的。_todesk命令行csdn

如何开发一个个人微信小程序,微信小程序开发入门教程_微信小程序怎么开发自己的小程序-程序员宅基地

文章浏览阅读10w+次,点赞183次,收藏1.1k次。做任何程序开发要首先找到其官方文档,我们先来看看其有哪些官方文档。微信小程序开发文档链接为:https://mp.weixin.qq.com/debug/wxadoc/dev/index.html,如下图:这里就是做微信小程序开发的全部官方文档。知道了文档的位置,下面我们来介绍下如何做一个微信小程序开发:第一步:下载微信小程序开发者工具并安装,下载路径:https://mp.weix..._微信小程序怎么开发自己的小程序

随便推点

Spring整合Activemq-程序员宅基地

文章浏览阅读7.6k次,点赞6次,收藏10次。spring整合activemq_spring整合activemq

语义分割入门的总结-程序员宅基地

文章浏览阅读740次。点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达作者:Yanpeng Sunhttps://zhuanlan.zhihu.com/p/74318967声明:仅做学术分..._语义分割两个目标重合怎么

SpringBoot实践(三十五):JVM信息分析_怎样查看springboot项目的jvm状态-程序员宅基地

文章浏览阅读902次。JVM分析可以也可以使用,那么什么时候用到jvm信息分析呢,一般生产测试环境,能够最大化将问题暴露,但是总有些问题只有生产运行很长时间后才会被发现,jvm分析经常用于运行了很久的系统有异常情况时的调优,比如堆内存本身分配不合理,新生代中eden比例太低等。_怎样查看springboot项目的jvm状态

基于springboot+vue的戒毒所人员管理系统 毕业设计-附源码251514_戒毒所管理系统-程序员宅基地

文章浏览阅读288次。戒毒所人员管理系统的开发是采用java语言,基于MVVM模式进行开发,采取MySQL作为后台数据的主要存储单元,采用Springboot框架实现了本系统的全部功能。戒毒所人员管理系统,具有戒毒人员管理、尿检管理、戒毒管理、治疗分类、社会跟踪等功能,本系统代码的复用率高,系统维护代价小,具有方便、灵活、高效等特征。_戒毒所管理系统

【LeetCode】面试题57 - II. 和为s的连续正数序列_leet code 和为s的正数序列 java-程序员宅基地

文章浏览阅读174次。来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof题目描述:输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。示例 1:输入:target = 9..._leet code 和为s的正数序列 java

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序