文章目录
Netty入门级应用实例_01_Hello Netty
0. 准备工作
- 添加pom依赖
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.31.Final</version> </dependency>
1. 执行流程分析
- 构建一对主从线程组
- 定义服务器启动类
- 为服务器设置Channel
- 设置处理从线程池的助手类初始化器
- 监听启动和关闭服务器
2. 代码实现
2.1 服务器端
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @program: study_netty
* @description: 实现客户端发送一个请求,服务端返回输出结果
* @author: Mr.superbeyone
* @create: 2018-11-20 11:12
**/
public class HelloServer {
public static void main(String[] args) throws Exception {
//定义一对线程组
//主线程组
EventLoopGroup boss = new NioEventLoopGroup();
//从线程组
EventLoopGroup work = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
//Netty服务器的创建 bootstrap是一个启动类
bootstrap.group(boss, work) //设置主从线程组
.channel(NioServerSocketChannel.class) //设置NIO的双向通道
.childHandler(new HelloServerInitializer()); //子处理器,用于处理work
//启动server,并且设置8888为启动端口,同时启动方式为同步
ChannelFuture channelFuture = bootstrap.bind(8888).sync();
//监听关闭的channel,设置为同步方式
channelFuture.channel().closeFuture().sync();
} finally {
//优雅的关闭
boss.shutdownGracefully();
work.shutdownGracefully();
}
}
}
2.2 子处理器
-
每个channel有多个handler共同组成管道(pipeline)
-
HelloServer初始化器代码实现
import com.superbeyone.netty.demo2.handler.CustomerHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* @program: study_netty
* @description: HelloServer初始化器
* @author: Mr.superbeyone
* @create: 2018-11-20 12:34
**/
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 通过socketChannel去获取对应的管道
ChannelPipeline pipeline = socketChannel.pipeline();
// 通过管道添加handler
// HttpServerCodec是由Netty自己提供的handler
// 当请求到服务端,我们需要做解码,响应到客户端编码
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
// 添加自定义handler,返回一个字符串
pipeline.addLast("CustomerHandler", new CustomerHandler());
}
}
2.3 自定义ChannelHandler
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* @program: study_netty
* @description: 创建自定义ChannelHandler
* @author: Mr.superbeyone
* @create: 2018-11-20 12:44
**/
public class CustomerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
// 获取channel
Channel channel = ctx.channel();
// 显示客户端的远程地址
System.out.println(channel.remoteAddress());
// 定义发送的数据消息
ByteBuf content = Unpooled.copiedBuffer("hello netty :) ~", CharsetUtil.UTF_8);
// 构建一个Http response
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
// 为响应设置数据类型和长度
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
// 把响应刷到客户端
ctx.writeAndFlush(response);
}
}