用Netty建立服务端, 首先我们应该新建立一个新的类, 作为服务端, 在其中写一个run方法, 作为启动:



1 public void run(){
 2         //  处理 Nio的Accept
 3         EventLoopGroup boss = new NioEventLoopGroup();
 4         //  处理 Nio的Read和Write事件
 5         EventLoopGroup worker = new NioEventLoopGroup();
 6         try {
 7             //  Netty中服务端启动类
 8             ServerBootstrap bootstrap = new ServerBootstrap();
 9             //  启动类配置启动类中加入两个线程组
10             bootstrap.group(boss, worker);
11             //  启动类配置Channel配置,Channel为异步TCP Socket连接
12             bootstrap.channel(NioServerSocketChannel.class);
13             //  启动类配置SO_BACKLOG 含义允许连接客户端数量为2000
14             bootstrap.option(ChannelOption.SO_BACKLOG, Socketbacklog);
15             //  启动类配置SO_REUSEADDR 含义地址复用, 允许重复使用本地地址和端口
16             bootstrap.option(ChannelOption.SO_REUSEADDR, true);
17             bootstrap.childHandlernew ChannelInitializer<SocketChannel>() { 
18                 @Override
19                 public void initChannel(SocketChannel ch) throws Exception {
20                     ch.pipeline().addLast(new ServerHandler()); //添加服务端的业务处理类
21                 }
22             });
23             //  保存Channel异步操作的结果
24             ChannelFuture channelFuture = bootstrap.bind(PORT).sync(); // 绑定端口, 并启动
25        
26             channelFuture.channel().closeFuture().sync(); // 关闭连接
27         } catch (Exception e) {
28              e.printStackTrace();
29         } finally { //优雅的关闭服务器
30             boss.shutdownGracefully();
31             worker.shutdownGracefully();
32         }
33     }   
34 }



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

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

 

在这个方法中, 第20行的位置我们添加了业务的处理类ServerHandler, 这个类是我们接下来需要写的, 它继承自ChannelInboundHandlerAdapter类, 通过重写其中的一些方法, 我们就可以进行我们想要的操作了:



1 public void channelActive(ChannelHandlerContext ctx) // 在channel被启用的时候触发 (在建立连接的时候)
2 public void channelRead(ChannelHandlerContext ctx, Object msg) // 在数据被接收的时候调用
3 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) // 出现报错时调用



msg是服务端接收到的数据, 而我们可以通过ctx.channel()方法来获取传来该值的channel

这里只列出了部分ChannelInboundHandlerAdapter中的方法, 其他的大家可以去查一下(其实这些方法命名十分简单明了了), 如果我们想讲客户端传来的数值都直接输出, 我们可以这样:



1     @Override
2     public void channelRead(ChannelHandlerContext ctx, Object msg) {
3         ctx.write(msg); 
4         ctx.flush(); 
5     }



如果我们想传值到服务端去, 我们可以先定义一个Channel = ctx.channel(), 早通过channel的writeAndFlush()方法将信息作为参数传到相应的客户端去