Netty-引导

引导类

点击加载

服务器致力于使用一个父Channel来接受来自客户端的连接,并创建子Channel以用于它们之间的通信;而客户端将最可能只需要一个单独的、没有父Channel的来用于它们所有的网络交互。(如UDP,基于无连接的传输协议,因为它们并不是每个连接都需要一个单独的Channel)

为什么引导类是Cloneable的?

有时可能需要创建多个具有类似配置或者完全相同配置的Channel。为了支持这种模式而又需要为每个Channel都创建并配置一个新的引导类实例。在一个已经配置完成的引导类实例上调用clone()方法将返回另一个可以立即使用的引导类实例。
这种方式只会创建引导类实例的EventLoopGroup的一个浅拷贝,所以EventLoopGroup将在所有克隆的Channel实例之间共享。

Channel和EventLoopGroup的兼容性

事件池(阻塞/非阻塞)要对应相应类型的管道。

点击加载

引导服务器

ServerChannel的实现负责创建子Channels,这些子Channel代表已经被接受的连接。

点击加载

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
//线程池的类型要和管道的类型兼容
NioEventLoopGroup group = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
//设置EventLoop, 其提供了用于处理Channel事件的EventLoop
serverBootstrap.group(group)
.channel(NioServerSocketChannel.class) //指定要实现的Channel
.childHandler(new SimpleChannelInboundHandler<ByteBuf>() {
//设置用于处理已被接受的子Channel的I/O及数据的ChannelInboundHandler
@Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf)
throws Exception{
System.out.println("received data");
}
});
//通过配置好的ServerBootstrap的实例绑定该Channel
ChannelFuture future = serverBootstrap.bind(new InetSocketAddress(8080));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if(channelFuture.isSuccess()) {
System.out.println("Server bound");
}
else{
System.err.println("Bound attempt failed");
channelFuture.cause().printStackTrace();
}
}
});

引导客户端

Boostrap类负责为客户端和使用无连接协议的应用程序创建Channel。

点击加载

下面的代码,引导了一个使用NIO TCP传输的客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioServerSocketChannel.class)
.handler(new SimpleChannelInboundHandler<ByteBuf>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf buf)
throws Exception{
System.out.println("Received data");
}
});
final ChannelFuture future = bootstrap.connect( //连接到远程主机
new InetSocketAddress("127.0.0.1", 80));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if(future.isSuccess()){
System.out.println("Connection established");
}
else{
System.err.println("Connection attempt failed");
future.cause().printStackTrace();
}
}
});

从Channel引导客户端

假设服务器正在处理一个客户端的请求,这个请求需要它充当第三方系统的客户端。当一个应用程序(如一个代理服务器)必须要和组织现有的系统(如Web服务或者服务数据库)集时,就可能发送这种情况。在这样情况下,将需要从已经被接受的子Channel中引导一个客户端Channel。

一个不创建额外的线程方法:通过将已被接受的子Channel的EventLoop传递给Bootstrap的group方法来共享该EventLoop。因为分配给EventLoop的所有的Channel都是使用同一个线程,所以这避免了额外的线程创建,这个共享的解决方案如下:

点击加载