共计 4250 个字符,预计需要花费 11 分钟才能阅读完成。
阅读目录
- 一、服务器端开发时序图
- 二、Netty 服务器端开发步骤
- 三、Netty 服务器开发示例代码
- 四、参考资料
一、服务器端开发时序图
图片来源:Netty 权威指南 (第 2 版)
二、Netty 服务器端开发步骤
使用 Netty 进行服务器端开发主要有以下几个步骤:
1、创建 ServerBootstrap 实例
ServerBootstrap b=new ServerBootstrap();
ServerBootstrap 是 Netty 服务器端的启动辅助类,提供了一系列的方法用于设置服务器端启动相关的参数。
2、设置并绑定 Reactor 线程池
EventLoopGroup bossGruop=new NioEventLoopGroup();// 用于服务器端接受客户端的连接 | |
EventLoopGroup workGroup=new NioEventLoopGroup();// 用于网络事件的处理 |
Netty 的线程池是 EventLoopGroup,它实际上是 EventLoop 的数组,EventLoop 职责是处理所有注册到本线程多路复用器 Selector 上的 Channel,Selector 的轮询操作是由绑定的 EventLoop 线程 run 方法驱动。
3、设置并绑定服务器端 Channel
b.group(bossGruop, workGroup).channel(NioServerSocketChannel.class)
Netty 对原生的 NIO 类库进行封装,作为 NIO 服务端,需要创建 ServerSocketChannel,对应的实现是 NioServerSocketChannel。
4、链路建立的时候创建并初始化 ChannelPipeline
b.group(bossGruop, workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>()
ChannelPipeline 的本质是一个负责处理网络事件的职责链,负责管理和执行 ChannelHandler。网络事件以事件流的形式在 ChannelPipeline 中流转,由 ChannelPipeline 根据 Channel|Handler 的执行策略调度 ChannelHandler 的执行。典型的网络事件有:
- 链路注册
- 链路激活
- 链路断开
- 接收到请求信息
- 请求信息接收并处理完毕
- 发送应答消息
- 链路发生异常
- 用户自定义事件
5、添加并设置 ChannelHandler
b.group(bossGruop, workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() | |
{ | |
@Override | |
protected void initChannel(SocketChannel arg0) throws Exception | |
{arg0.pipeline().addLast(new HelloServerHandler()); | |
} | |
}).option(ChannelOption.SO_BACKLOG, 1024); |
ChannelHandler 是 Netty 提供给用户定制和扩展的接口,例如消息编解码、心跳、安全认证、TSL/SSL 认证
6、绑定并启动监听窗口
ChannelFuture f=b.bind(port).sync();
经过一系列初始化和检测工作后,会启动监听端口,并将 ServerSocketChannel 注册到 Selector 上监听客户端连接
7、Selector 轮询
由 Reactor 线程 NioEventLoop 负责调度和执行 Selector 轮询操作,选择准备就绪的 Channel 集合
8、当轮询到准备就绪的 Channel 之后,就由 Reactor 线程 NioEventLoop 执行 ChannelPipeline 的相应方法,最终调度并执行 ChannelHandler
public class HelloServerHandler extends ChannelHandlerAdapter
三、Netty 服务器开发示例代码
需求:服务器端实现,每连接一个客户端,在服务器控制台打印客户端输入的字符。(注:本代码使用的 netty 是 netty-all-5.0.0.Alpha1-sources.jar 版本)
服务器端代码如下:
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; | |
//Netty 服务器端 | |
public class HelloServer | |
{private int port; | |
public HelloServer(int port) | |
{super(); | |
this.port = port; | |
} | |
private void bind() throws InterruptedException | |
{EventLoopGroup bossGruop=new NioEventLoopGroup();// 用于服务器端接受客户端的连接 | |
EventLoopGroup workGroup=new NioEventLoopGroup();// 用于网络事件的处理 | |
try | |
{ServerBootstrap b=new ServerBootstrap(); | |
b.group(bossGruop, workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() | |
{ | |
protected void initChannel(SocketChannel arg0) throws Exception | |
{arg0.pipeline().addLast(new HelloServerHandler()); | |
} | |
}).option(ChannelOption.SO_BACKLOG, 1024);// 指定此套接口排队的最大连接个数 | |
ChannelFuture f=b.bind(port).sync(); | |
f.channel().closeFuture().sync();} | |
finally | |
{bossGruop.shutdownGracefully(); | |
workGroup.shutdownGracefully();} | |
} | |
public static void main(String[] args) throws InterruptedException | |
{new HelloServer(8080).bind();} | |
} |
import io.netty.buffer.ByteBuf; | |
import io.netty.channel.ChannelHandlerAdapter; | |
import io.netty.channel.ChannelHandlerContext; | |
// 自定义的 ChannelHandler | |
public class HelloServerHandler extends ChannelHandlerAdapter | |
{ | |
public void channelActive(ChannelHandlerContext ctx) throws Exception | |
{System.out.println("客户端连上了..."); | |
} | |
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception | |
{ByteBuf buf=(ByteBuf) msg; | |
byte[] req=new byte[buf.readableBytes()]; | |
buf.readBytes(req); | |
System.out.println("服务器端接收的消息:"+new String(req)); | |
} | |
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception | |
{ctx.flush(); | |
} | |
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception | |
{ctx.close(); | |
} | |
} |
客户端:使用 telnet 模拟客户端输入,
按住“ctrl+]”,然后输入指令 send a
四、参考资料
1、Netty 权威指南 (李林峰)【Netty 权威指南 PDF 完整版带目录书签 + 源码 下载地址 http://www.linuxidc.com/Linux/2016-07/133575.htm】
运用 Spring 注解实现 Netty 服务器端 UDP 应用程序 http://www.linuxidc.com/Linux/2013-09/89780.htm
Netty 源码学习笔记 http://www.linuxidc.com/Linux/2013-09/89778.htm
Netty 使用实例 http://www.linuxidc.com/Linux/2013-09/89779.htm
Java NIO 框架 –Netty4 的简单示例 http://www.linuxidc.com/Linux/2015-01/111335.htm
Netty 的详细介绍 :请点这里
Netty 的下载地址 :请点这里
本文永久更新链接地址 :http://www.linuxidc.com/Linux/2016-07/133584.htm
