netty是如何工作的:实现自己的第一个netty server
兴趣是最好的老师,当你对一件事情感兴趣的时候,你就更容易长久地坚持下去,从而达到一个更高的高度,或许还能够取得意想不到的效果。接下来我会从实现一个 echo server 开始 netty 的探索旅程,如果你也对 netty 感兴趣,那么我们就开始吧。
正如学习一门语言是从 hello world 开始一样,学习一个网络框架通常是从 echo server 开始的。
echo server 启动后会监听一个指定的端口,等待你连接并输入字符,它要做的就是原封不动地将你的输入返回给你。
1 | hello // 客户端输入「hello」 |
要通过 netty 实现一个 echo server,它的核心代码非常简单,简单到只有一行代码,是不是很不可思议
1 | ctx.writeAndFlush(msg); |
这行代码中 msg
是接收到的 client 端的输入信息,writeAndFlush
则是将指定信息发送给 client
当然我们还要写一些其他的代码,netty 是一个框架,那么我们就要按照框架的约定来写。
netty 将 client 与 server 之间的连接抽象为 channel,通过 ChannelInboundHandler
监听 channel 上的输入事件。
对于 echo server 来说,我们需要监听的是 channelRead 事件,那么只需要对该事件的处理行为进行定义。
为了方便,通常不会选择直接实现 ChannelInboundHandler 接口,而是继承 ChannelInboundHandlerAdapter 类,这样就不用写其他输入事件的实现了。
说到这里,你就可以明白下面这段代码是做什么的了
1 | public class EchoServerHandler extends ChannelInboundHandlerAdapter { |
仅仅有这些还是不够,我们还需要监听指定的端口,接收 client 的连接请求,在建立连接之后才会用到我们的 EchoServerHandler
这一切也是相当简单,只需要按照 netty 的固定模式使用就可以了。我们需要一个 main 方法作为程序的启动入口,这很好理解
1 | public class EchoServer { |
接下来是创建一个 EchoServerHandler 的实例,我们希望用它来处理所有的请求。因为它本身是无状态的,所以多个连接共享同一个实例是没有问题的。
1 | final EchoServerHandler serverHandler = new EchoServerHandler(); |
接下来需要创建一个启动类,它负责 server 的启动管理
1 | ServerBootstrap b = new ServerBootstrap(); |
我们需要告诉它一些必要的信息,包括要采用哪种 IO 模型实现、对应的 EventLoopGroup(这里可以简单地把它当做线程池来理解)、用于自定义业务处理逻辑的 ChannelHandler
我们计划采用 NIO 模型的 NioServerSocketChannel 系列,对应的 EventLoopGroup 实现是 NioEventLoopGroup,总之这两个配套就可以,不理解也没关系
1 | // NioServerSocketChannel和NioEventLoopGroup搭配干活 |
Server 本身的配置就这些了,已经足够用来启动并建立连接了。别忘了我们是要做 Echo server,还要将 EchoServerHandler 用上,这一切就在这几行代码
1 | b.childHandler(new ChannelInitializer<SocketChannel>() { |
你可以将它理解为固定的模式,其实核心也就只有一行代码 p.addLast(serverHandler)
。这段代码的作用是:当 client 与 server 建立连接后,将 serverHandler 添加到连接的 pipeline 链上
接下来就是通过 ServerBootStrap 启动 server 了,我们计划将 server 绑定到 localhost 的 8110 端口,它也只有一行代码:
1 | ChannelFuture f = b.bind(8110).sync(); |
好了,我们所有的代码都写完了,执行 main 方法测试一下吧。
稍等,这里有个问题,我们的 echo server 启动后过一会就直接退出,因为 main 方法执行完了。为了让 server 一直执行,我们再加一行代码,只有当程序告诉它要退出时才会退出
1 | f.channel().closeFuture().sync(); |
启动 server 测试一下吧。直接执行 main 方法,server 已启动。
client 要怎么连呢,我们还没写 client 呢。问题不大,可以通过 nc 连接,这个工具很好用
1 | nc localhost 8110 |
看到了吗,它已经连上 server 等待我们的输入了
1 | ➜ netty git:(4.1) ✗ nc localhost 8110 |
输入 hello 并回车,它会再打印一个 hello 并且换行,等待下次输入
1 | ➜ netty git:(4.1) ✗ nc localhost 8110 |
好了,已经完工了,我把 EchoServer 类的代码贴在下面,你可以试下了
1 | public class EchoServer { |
你可能看到多了一行 group.shutdownGracefully();
,它是用于优雅退出的,具体做了什么,以后再聊。
- 2021-08-08
学习一门新的语言,通常是以 HelloWorld 开始的。类似地,学习一个网络框架,通常是以 EchoServer 开始的。接下来我们就来看下如何通过 netty 实现一个 EchoServer。
- 2021-04-14
Netty server 在启动过程中会触发一系列的 Inbound 事件,它的流程是怎样的呢?
- 2021-01-26
ServerBootstrap 启动时需要初始化 ServerSocketChannel 并将其绑定到 EventLoop 上,用于处理该 channel 上产生的各种事件。那么 ServerSocketChannel 是如何完成创建和初始化的?又是如何绑定到 EventLoop 上的?
- 2022-01-30
在上一篇文章中,我们了解了如何通过 netty 实现一个echo server。你应该还记得
ServerBootstrap
启动类,它负责 server 的启动管理,在启动前我们需要为其配置EventLoopGroup
。EventLoopGroup
有配套的ServerSocketChannel
,比如通常使用最多的是NioEventLoopGroup
,它就需要和NioServerSocketChannel
搭配起来工作。 - 2017-06-20
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
Quick Start
Create a new post
1
$ hexo new "My New Post"