mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-11-15 13:43:50 +08:00
u
This commit is contained in:
@@ -25,13 +25,7 @@
|
||||
<meta name="generator" content="Hexo 4.2.0">
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
<div class="book-container">
|
||||
|
||||
<div class="book-sidebar">
|
||||
@@ -55,421 +49,214 @@
|
||||
<li><a href="/" class="current-tab">首页</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<ul class="uncollapsible">
|
||||
|
||||
<li><a href="../">上一级</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<ul class="uncollapsible">
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/00 学好 Netty,是你修炼 Java 内功的必经之路.md.html">00 学好 Netty,是你修炼 Java 内功的必经之路.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/01 初识 Netty:为什么 Netty 这么流行?.md.html">01 初识 Netty:为什么 Netty 这么流行?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/02 纵览全局:把握 Netty 整体架构脉络.md.html">02 纵览全局:把握 Netty 整体架构脉络.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
<a class="current-tab" href="/专栏/Netty 核心原理剖析与 RPC 实践-完/03 引导器作用:客户端和服务端启动都要做些什么?.md.html">03 引导器作用:客户端和服务端启动都要做些什么?.md.html</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/04 事件调度层:为什么 EventLoop 是 Netty 的精髓?.md.html">04 事件调度层:为什么 EventLoop 是 Netty 的精髓?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/05 服务编排层:Pipeline 如何协调各类 Handler ?.md.html">05 服务编排层:Pipeline 如何协调各类 Handler ?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/06 粘包拆包问题:如何获取一个完整的网络包?.md.html">06 粘包拆包问题:如何获取一个完整的网络包?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/07 接头暗语:如何利用 Netty 实现自定义协议通信?.md.html">07 接头暗语:如何利用 Netty 实现自定义协议通信?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/08 开箱即用:Netty 支持哪些常用的解码器?.md.html">08 开箱即用:Netty 支持哪些常用的解码器?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/09 数据传输:writeAndFlush 处理流程剖析.md.html">09 数据传输:writeAndFlush 处理流程剖析.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/10 双刃剑:合理管理 Netty 堆外内存.md.html">10 双刃剑:合理管理 Netty 堆外内存.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/11 另起炉灶:Netty 数据传输载体 ByteBuf 详解.md.html">11 另起炉灶:Netty 数据传输载体 ByteBuf 详解.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/12 他山之石:高性能内存分配器 jemalloc 基本原理.md.html">12 他山之石:高性能内存分配器 jemalloc 基本原理.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/13 举一反三:Netty 高性能内存管理设计(上).md.html">13 举一反三:Netty 高性能内存管理设计(上).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/14 举一反三:Netty 高性能内存管理设计(下).md.html">14 举一反三:Netty 高性能内存管理设计(下).md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/15 轻量级对象回收站:Recycler 对象池技术解析.md.html">15 轻量级对象回收站:Recycler 对象池技术解析.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/16 IO 加速:与众不同的 Netty 零拷贝技术.md.html">16 IO 加速:与众不同的 Netty 零拷贝技术.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/17 源码篇:从 Linux 出发深入剖析服务端启动流程.md.html">17 源码篇:从 Linux 出发深入剖析服务端启动流程.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/18 源码篇:解密 Netty Reactor 线程模型.md.html">18 源码篇:解密 Netty Reactor 线程模型.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/19 源码篇:一个网络请求在 Netty 中的旅程.md.html">19 源码篇:一个网络请求在 Netty 中的旅程.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/20 技巧篇:Netty 的 FastThreadLocal 究竟比 ThreadLocal 快在哪儿?.md.html">20 技巧篇:Netty 的 FastThreadLocal 究竟比 ThreadLocal 快在哪儿?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/21 技巧篇:延迟任务处理神器之时间轮 HashedWheelTimer.md.html">21 技巧篇:延迟任务处理神器之时间轮 HashedWheelTimer.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/22 技巧篇:高性能无锁队列 Mpsc Queue.md.html">22 技巧篇:高性能无锁队列 Mpsc Queue.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/23 架构设计:如何实现一个高性能分布式 RPC 框架.md.html">23 架构设计:如何实现一个高性能分布式 RPC 框架.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/24 服务发布与订阅:搭建生产者和消费者的基础框架.md.html">24 服务发布与订阅:搭建生产者和消费者的基础框架.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/25 远程通信:通信协议设计以及编解码的实现.md.html">25 远程通信:通信协议设计以及编解码的实现.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/26 服务治理:服务发现与负载均衡机制的实现.md.html">26 服务治理:服务发现与负载均衡机制的实现.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/27 动态代理:为用户屏蔽 RPC 调用的底层细节.md.html">27 动态代理:为用户屏蔽 RPC 调用的底层细节.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/28 实战总结:RPC 实战总结与进阶延伸.md.html">28 实战总结:RPC 实战总结与进阶延伸.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/29 编程思想:Netty 中应用了哪些设计模式?.md.html">29 编程思想:Netty 中应用了哪些设计模式?.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/30 实践总结:Netty 在项目开发中的一些最佳实践.md.html">30 实践总结:Netty 在项目开发中的一些最佳实践.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/专栏/Netty 核心原理剖析与 RPC 实践-完/31 结束语 技术成长之路:如何打造自己的技术体系.md.html">31 结束语 技术成长之路:如何打造自己的技术体系.md.html</a>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||||
|
||||
<div class="sidebar-toggle-inner"></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
function add_inner() {
|
||||
@@ -479,9 +266,6 @@
|
||||
inner.classList.add('show')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function remove_inner() {
|
||||
|
||||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||||
@@ -489,9 +273,6 @@
|
||||
inner.classList.remove('show')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function sidebar_toggle() {
|
||||
|
||||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||||
@@ -521,9 +302,6 @@
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function open_sidebar() {
|
||||
|
||||
let sidebar = document.querySelector('.book-sidebar')
|
||||
@@ -547,13 +325,7 @@ function hide_canvas() {
|
||||
overlay.classList.remove('show')
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<div class="off-canvas-content">
|
||||
|
||||
<div class="columns">
|
||||
@@ -619,129 +391,36 @@ function hide_canvas() {
|
||||
<p>所有 Netty 服务端的启动类都可以采用如下代码结构进行开发。简单梳理一下流程:首先创建引导器;然后配置线程模型,通过引导器绑定业务逻辑处理器,并配置一些网络参数;最后绑定端口,就可以完成服务器的启动了。</p>
|
||||
|
||||
<pre><code>public class HttpServer {
|
||||
|
||||
|
||||
|
||||
public void start(int port) throws Exception {
|
||||
|
||||
|
||||
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||
|
||||
|
||||
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
|
||||
|
||||
|
||||
b.group(bossGroup, workerGroup)
|
||||
|
||||
|
||||
|
||||
.channel(NioServerSocketChannel.class)
|
||||
|
||||
|
||||
|
||||
.localAddress(new InetSocketAddress(port))
|
||||
|
||||
|
||||
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
|
||||
|
||||
public void initChannel(SocketChannel ch) {
|
||||
|
||||
|
||||
|
||||
ch.pipeline()
|
||||
|
||||
|
||||
|
||||
.addLast("codec", new HttpServerCodec()) // HTTP 编解码
|
||||
|
||||
|
||||
|
||||
.addLast("compressor", new HttpContentCompressor()) // HttpContent 压缩
|
||||
|
||||
|
||||
|
||||
.addLast("aggregator", new HttpObjectAggregator(65536)) // HTTP 消息聚合
|
||||
|
||||
|
||||
|
||||
.addLast("handler", new HttpServerHandler()); // 自定义业务逻辑处理器
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
|
||||
|
||||
ChannelFuture f = b.bind().sync();
|
||||
|
||||
|
||||
|
||||
System.out.println("Http Server started, Listening on " + port);
|
||||
|
||||
|
||||
|
||||
f.channel().closeFuture().sync();
|
||||
|
||||
|
||||
|
||||
} finally {
|
||||
|
||||
|
||||
|
||||
workerGroup.shutdownGracefully();
|
||||
|
||||
|
||||
|
||||
bossGroup.shutdownGracefully();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
|
||||
|
||||
new HttpServer().start(8088);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
@@ -751,45 +430,15 @@ function hide_canvas() {
|
||||
<p>如下代码所示,HttpServerHandler 是业务自定义的逻辑处理类。它是入站 ChannelInboundHandler 类型的处理器,负责接收解码后的 HTTP 请求数据,并将请求处理结果写回客户端。</p>
|
||||
|
||||
<pre><code>public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {
|
||||
|
||||
|
||||
|
||||
String content = String.format("Receive http request, uri: %s, method: %s, content: %s%n", msg.uri(), msg.method(), msg.content().toString(CharsetUtil.UTF_8));
|
||||
|
||||
|
||||
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||
|
||||
|
||||
|
||||
HttpVersion.HTTP_1_1,
|
||||
|
||||
|
||||
|
||||
HttpResponseStatus.OK,
|
||||
|
||||
|
||||
|
||||
Unpooled.wrappedBuffer(content.getBytes()));
|
||||
|
||||
|
||||
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
@@ -807,9 +456,6 @@ function hide_canvas() {
|
||||
<p>测试结果输出如下:</p>
|
||||
|
||||
<pre><code>$ curl http://localhost:8088/abc
|
||||
|
||||
|
||||
|
||||
$ Receive http request, uri: /abc, method: GET, content:
|
||||
|
||||
</code></pre>
|
||||
@@ -843,13 +489,7 @@ $ Receive http request, uri: /abc, method: GET, content:
|
||||
<p>Reactor 单线程模型所有 I/O 操作都由一个线程完成,所以只需要启动一个 EventLoopGroup 即可。</p>
|
||||
|
||||
<pre><code>EventLoopGroup group = new NioEventLoopGroup(1);
|
||||
|
||||
|
||||
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
|
||||
|
||||
|
||||
b.group(group)
|
||||
|
||||
</code></pre>
|
||||
@@ -859,13 +499,7 @@ b.group(group)
|
||||
<p>Reactor 单线程模型有非常严重的性能瓶颈,因此 Reactor 多线程模型出现了。在 Netty 中使用 Reactor 多线程模型与单线程模型非常相似,区别是 NioEventLoopGroup 可以不需要任何参数,它默认会启动 2 倍 CPU 核数的线程。当然,你也可以自己手动设置固定的线程数。</p>
|
||||
|
||||
<pre><code>EventLoopGroup group = new NioEventLoopGroup();
|
||||
|
||||
|
||||
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
|
||||
|
||||
|
||||
b.group(group)
|
||||
|
||||
</code></pre>
|
||||
@@ -875,17 +509,8 @@ b.group(group)
|
||||
<p>在大多数场景下,我们采用的都是<strong>主从多线程 Reactor 模型</strong>。Boss 是主 Reactor,Worker 是从 Reactor。它们分别使用不同的 NioEventLoopGroup,主 Reactor 负责处理 Accept,然后把 Channel 注册到从 Reactor 上,从 Reactor 主要负责 Channel 生命周期内的所有 I/O 事件。</p>
|
||||
|
||||
<pre><code>EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||
|
||||
|
||||
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
|
||||
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
|
||||
|
||||
|
||||
b.group(bossGroup, workerGroup)
|
||||
|
||||
</code></pre>
|
||||
@@ -909,41 +534,14 @@ b.group(bossGroup, workerGroup)
|
||||
<p>在 Netty 中可以通过 ChannelPipeline 去注册多个 ChannelHandler,每个 ChannelHandler 各司其职,这样就可以实现最大化的代码复用,充分体现了 Netty 设计的优雅之处。那么如何通过引导器添加多个 ChannelHandler 呢?其实很简单,我们看下 HTTP 服务器代码示例:</p>
|
||||
|
||||
<pre><code>b.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
|
||||
|
||||
public void initChannel(SocketChannel ch) {
|
||||
|
||||
|
||||
|
||||
ch.pipeline()
|
||||
|
||||
|
||||
|
||||
.addLast("codec", new HttpServerCodec())
|
||||
|
||||
|
||||
|
||||
.addLast("compressor", new HttpContentCompressor())
|
||||
|
||||
|
||||
|
||||
.addLast("aggregator", new HttpObjectAggregator(65536))
|
||||
|
||||
|
||||
|
||||
.addLast("handler", new HttpServerHandler());
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
</code></pre>
|
||||
@@ -1063,145 +661,40 @@ b.group(bossGroup, workerGroup)
|
||||
<h4>HTTP 客户端类</h4>
|
||||
|
||||
<pre><code>public class HttpClient {
|
||||
|
||||
|
||||
|
||||
public void connect(String host, int port) throws Exception {
|
||||
|
||||
|
||||
|
||||
EventLoopGroup group = new NioEventLoopGroup();
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
|
||||
Bootstrap b = new Bootstrap();
|
||||
|
||||
|
||||
|
||||
b.group(group);
|
||||
|
||||
|
||||
|
||||
b.channel(NioSocketChannel.class);
|
||||
|
||||
|
||||
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
|
||||
|
||||
b.handler(new ChannelInitializer<SocketChannel>() {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
|
||||
|
||||
public void initChannel(SocketChannel ch) {
|
||||
|
||||
|
||||
|
||||
ch.pipeline().addLast(new HttpResponseDecoder());
|
||||
|
||||
|
||||
|
||||
ch.pipeline().addLast(new HttpRequestEncoder());
|
||||
|
||||
|
||||
|
||||
ch.pipeline().addLast(new HttpClientHandler());
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
ChannelFuture f = b.connect(host, port).sync();
|
||||
|
||||
|
||||
|
||||
URI uri = new URI("http://127.0.0.1:8088");
|
||||
|
||||
|
||||
|
||||
String content = "hello world";
|
||||
|
||||
|
||||
|
||||
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
|
||||
|
||||
|
||||
|
||||
uri.toASCIIString(), Unpooled.wrappedBuffer(content.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
|
||||
|
||||
request.headers().set(HttpHeaderNames.HOST, host);
|
||||
|
||||
|
||||
|
||||
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
|
||||
|
||||
|
||||
request.headers().set(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes());
|
||||
|
||||
|
||||
|
||||
f.channel().write(request);
|
||||
|
||||
|
||||
|
||||
f.channel().flush();
|
||||
|
||||
|
||||
|
||||
f.channel().closeFuture().sync();
|
||||
|
||||
|
||||
|
||||
} finally {
|
||||
|
||||
|
||||
|
||||
group.shutdownGracefully();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
|
||||
|
||||
|
||||
client.connect("127.0.0.1", 8088);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
@@ -1209,45 +702,15 @@ b.group(bossGroup, workerGroup)
|
||||
<h4>客户端业务处理类</h4>
|
||||
|
||||
<pre><code>public class HttpClientHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
||||
|
||||
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
|
||||
|
||||
|
||||
if (msg instanceof HttpContent) {
|
||||
|
||||
|
||||
|
||||
HttpContent content = (HttpContent) msg;
|
||||
|
||||
|
||||
|
||||
ByteBuf buf = content.content();
|
||||
|
||||
|
||||
|
||||
System.out.println(buf.toString(io.netty.util.CharsetUtil.UTF_8));
|
||||
|
||||
|
||||
|
||||
buf.release();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
@@ -1271,9 +734,6 @@ b.group(bossGroup, workerGroup)
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1281,9 +741,6 @@ b.group(bossGroup, workerGroup)
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||||
|
||||
</div>
|
||||
@@ -1299,17 +756,11 @@ b.group(bossGroup, workerGroup)
|
||||
<script>
|
||||
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
|
||||
|
||||
function gtag() {
|
||||
|
||||
dataLayer.push(arguments);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-NPSEEVD756');
|
||||
@@ -1335,9 +786,6 @@ b.group(bossGroup, workerGroup)
|
||||
setCookie("lastPath", path)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setCookie(cname, cvalue) {
|
||||
|
||||
var d = new Date();
|
||||
@@ -1349,9 +797,6 @@ b.group(bossGroup, workerGroup)
|
||||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getCookie(cname) {
|
||||
|
||||
var name = cname + "=";
|
||||
@@ -1369,12 +814,6 @@ b.group(bossGroup, workerGroup)
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user