我是靠谱客的博主 美丽红牛,这篇文章主要介绍netty快速入门什么是netty让我们开始吧开始之前先来个丢弃服务先创建一个处理器编写服务端代码查看收到的数据写个应答服务器,现在分享给大家,希望可以做个参考。

什么是netty

Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能、高可靠性协议的服务器和客户端。换句话说,Netty 是一个 NIO 客户端服务器框架,使用它可以快速简单地开发网络应用程序,比如服务器和客户端的协议。Netty 大大简化了网络程序的开发过程比如 TCP 和 UDP 的 socket 服务的开发。

"快速和简单"并不意味着应用程序会有难维护和性能低的问题,Netty 是一个精心设计的框架,它从许多协议的实现中吸收了很多的经验比如 FTP、SMTP、HTTP、许多二进制和基于文本的传统协议.因此,Netty 已经成功地找到一个方式,在不失灵活性的前提下来实现开发的简易性,高性能,稳定性。

让我们开始吧

本章围绕 Netty 的核心架构,通过简单的示例带你快速入门。当你读完本章节,你马上就可以用 Netty 写出一个客户端和服务器。

开始之前

在开始之前我们先说明下开发环境,我们使用netty-4.1.30这个版本,jdk使用1.8及以上版本。

复制代码
1
2
3
4
5
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.30.Final</version> </dependency>

jdk请自行下载。

先来个丢弃服务

世上最简单的协议不是'Hello, World!' 而是 DISCARD(丢弃)。这个协议将会丢掉任何收到的数据,而不响应。 为了实现 DISCARD 协议,你只需忽略所有收到的数据。让我们从 handler (处理器)的实现开始,handler 是由Netty 生成用来处理 I/O 事件的。

先创建一个处理器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.netty.first; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; /** * 处理服务端 channel. */ public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1) @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2) System.out.println(msg); // 默默地丢弃收到的数据 ((ByteBuf) msg).release(); // (3) } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4) // 当出现异常就关闭连接cause.printStackTrace(); ctx.close(); }

 

(1)ChannelInboundHandlerAdapter提供了许多事件处理的接口方法,然后你可以覆盖这些方法。现在仅仅只需要继承 类而不是你自己去实现接口方法。

(2)这里我们盖了chanelRead()覆 事件处理方法。每当从客户端收到新的数据时,这个方法会在收到消息时被调用,这个ByteBuf例子中,收到的消息的类型是

(3)为了实现 DISCARD 协议,处理器不得不忽略所有接受到的消息。

ByteBuf是一个引用计数对象,这个对象必须显示地调用 release() 方法来释放。请记住处理器的职责是释放所有channelRead()传递到处理器的引用计数对象。通常, 方法的实现就像下面的这段代码:

复制代码
1
2
3
4
5
6
7
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { try { // Do something with msg } finally { ReferenceCountUtil.release(msg); } }

(4)exceptiongcaught()事件处理方法是当出现throwable对象才会被调用,即当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时。在大部分情况下,捕获的异常应该被记录下来并且把关联的 channel 给关闭掉。然而这个方法的处理方式会在遇到不同异常的情况下有不同的实现,比如你可能想在关闭连接之前发送一个错误码的响应消息。

编写服务端代码

目前为止一切都还不错,我们已经实现了 DISCARD 服务器的一半功能,剩下的需要编写一个 main() 方法来启动DiscardServerHandler服务端的 。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.netty.first; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; /** * 丢弃任何进入的数据 */ public class DiscardServer { private int port; public DiscardServer(int port) { this.port = port; } public void run() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); // (2) b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // (3) .childHandler(new ChannelInitializer<SocketChannel>() { // (4) @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new DiscardServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) // (5) .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) // 绑定端口,开始接收进来的连接 ChannelFuture f = b.bind(port).sync(); // (7) // 等待服务器 socket 关 闭 。 // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。 f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new DiscardServer(port).run(); } }

NioEventLoopGroup 用来处理I/O操作的多线程事件循环器,Netty 提供了许多不同的EventLoopGroup 的NioEventLoopGroup实现用来处理不同的传输。在这个例子中我们实现了一个服务端的应用,因此会有2个会被使用。第一个经常被叫做'boss',用来接收进来的连接。第二个经常被叫做'worker',用来处理已经被接收的连接,一旦'boss'接收到连接,就会把连接信息注册到'worker'上。如何知道多少个线程已经被使用,如何映射到已经创建 的 Channel上都需要依赖于 EventLoopGroup 的实现,并且可以通过构造函数来配置他们的关系。

2. ServerBootstrap 是一个启动 NIO 服务的辅助启动类。你可以在这个服务中直接使用 Channel,但是这会是一个复杂的处理过程,在很多情况下你并不需要这样做。

3. 这里我们指定使用 NioServerSocketChannel 类来举例说明一个新的 Channel 如何接收进来的连接。

4. 这里的事件处理类经常会被用来处理一个最近的已经接收的 Channel。ChannelInitializer 是一个特殊的处理类,他的目的是帮助使用者配置一个新的 Channel。也许你想通过增加一些处理类比如DiscardServerHandler 来配置一个新的 Channel 或者其对应的ChannelPipeline 来实现你的网络程序。当你的程序变的复杂时,可能你会增加更多的处理类到 pipline 上,然后提取这些匿名类到最顶层的类上。

5. 你可以设置这里指定的 Channel 实现的配置参数。我们正在写一个TCP/IP 的服务端,因此我们被允许设置socket 的参数选项比如tcpNoDelay 和 keepAlive。请参考 ChannelOption 和详细的 ChannelConfig 实现的接口文档以此可以对ChannelOption 的有一个大概的认识。

6. 你关注过 option() 和 childOption() 吗?option() 是提供给NioServerSocketChannel 用来接收进来的连接。childOption() 是提供给由父管道 ServerChannel 接收到的连接,在这个例子中也是 NioServerSocketChannel。

7. 我们继续,剩下的就是绑定端口然后启动服务。这里我们在机器上绑定了机器所有网卡上的 8080 端口。当然现在你可以多次调用 bind() 方法(基于不同绑定地址)。

恭喜!你已经熟练地完成了第一个基于 Netty 的服务端程序。

查看收到的数据

telnet localhost 8080现在我们已经编写出我们第一个服务端,我们需要测试一下他是否真的可以运行。最简单的测试方法是用 telnet 命

令。例如,你可以在命令行上输入 或者其他类型参数。

netty快速入门

 

netty快速入门

 

在telnet终端中输入任意字符,服务端向控制台输出信息。证明服务端接收到客户端发送的消息了。但是我们并不 能看到服务端接收到了什么东西,我们可以把channelRead方法改成如下内容:

复制代码
1
2
3
4
5
6
7
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2) //System.out.println(msg); ByteBuf message = (ByteBuf) msg; System.out.println(message.toString(CharsetUtil.US_ASCII)); // 默默地丢弃收到的数据 ((ByteBuf) msg).release(); // (3) }

这样控制台就可以看到客户端发送的数据了。

netty快速入门

 

写个应答服务器

 

到目前为止,我们虽然接收到了数据,但没有做任何的响应。然而一个服务端通常会对一个请求作出响应。让我们 学习怎样在 ECHO 协议的实现下编写一个响应消息给客户端,这个协议针对任何接收的数据都会返回一个响应。

和 discard server 唯一不同的是把在此之前我们实现的 channelRead() 方法,返回所有的数据替代打印接收数据到控制台上的逻辑。因此,需要把 channelRead() 方法修改如下:

复制代码
1
2
3
4
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ctx.write(msg); // (1) ctx.flush(); // (2) }

(1)ChannelHandlerContext 对象提供了许多操作,使你能够触发各种各样的 I/O 事件和操作。这里我们调用了write(Object) 方法来逐字地把接受到的消息写入。请注意不同于 DISCARD 的例子我们并没有释放接受到的消息, 这是因为当写入的时候 Netty 已经帮我们释放了。 (2)ctx.write(Object) 方法不会使消息写入到通道上,他被缓冲在了内部,你需要调用 ctx.flush() 方法来把缓冲区中数据强行输出。或者你可以用更简洁的cxt.writeAndFlush(msg) 以达到同样的目的。

如果你再一次运行 telnet 命令,你会看到服务端会发回一个你已经发送的消息。

最后

以上就是美丽红牛最近收集整理的关于netty快速入门什么是netty让我们开始吧开始之前先来个丢弃服务先创建一个处理器编写服务端代码查看收到的数据写个应答服务器的全部内容,更多相关netty快速入门什么是netty让我们开始吧开始之前先来个丢弃服务先创建一个处理器编写服务端代码查看收到内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部