Hello World 入门(注意看注释)
gradle依赖
dependencies {
// https://mvnrepository.com/artifact/io.netty/netty-all
compile group: 'io.netty', name: 'netty-all', version: '4.1.30.Final'
}
Server.java
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;
public class Server {
public static void main(String[] args) throws Exception {
/**
* 1. netty推荐使用两个线程组处理事务
*/
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
/**
* 2. 用于启动服务端的类
*/
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new MyServerInitiallizer());
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
MyServerInitiallizer.java
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
public class MyServerInitiallizer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("httpServerCodec", new HttpServerCodec());
pipeline.addLast("myHttpServerHandler", new MyHttpServerHandler());
}
}
MyHttpServerHandler.java
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
public class MyHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
/**
* 0. 读取客户端发过来的请求,并将响应返回给客户端的方法
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if(msg instanceof HttpRequest) {
/**
* 1. 构建响应的字符串信息
*/
ByteBuf content = Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8);
/**
* 2. 构建FullHttpResponse 对象
*/
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
/**
* 3. 设置 response 的头信息
*/
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
/**
* 4. 将response对象返回到客户端
*/
ctx.writeAndFlush(response);
}
}
}
启动服务器,使用curl请求结果如下:
D:\Program Files\curl>curl "http://localhost:8899"
hello world
netty的执行流程:
修改 MyHttpServerHandler.java 为如下代码:
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
import java.net.URI;
public class MyHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {
/**
* 0. 读取客户端发过来的请求,并将响应返回给客户端的方法
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if(msg instanceof HttpRequest) {
System.out.println("执行channelRead0");
HttpRequest httpRequest = (HttpRequest) msg;
URI uri = new URI(httpRequest.uri());
if("/favicon.ico".equals(uri.getPath())){
System.out.println("请求.favicon.ico");
return;
}
/**
* 1. 构建响应的字符串信息
*/
ByteBuf content = Unpooled.copiedBuffer("hello world", CharsetUtil.UTF_8);
/**
* 2. 构建FullHttpResponse 对象
*/
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
/**
* 3. 设置 response 的头信息
*/
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
/**
* 4. 将response对象返回到客户端
*/
ctx.writeAndFlush(response);
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("MyHttpServerHandler.channelActive");
super.channelActive(ctx);
}
/**
* ChannelHandlerContext: 实例是 DefaultChannelHandlerContext
* 包含了一个ChannelHandler,这里是 MyHttpServerHandler 的实例
* 包含了一个 DefaultChannelPipeline pipeline:就是 MyServerInitiallizer#initChannel方法里面的 pipeline
* DefaultChannelPipeline{(httpServerCodec = io.netty.handler.codec.http.HttpServerCodec), (myHttpServerHandler = com.ghq.netty.one.MyHttpServerHandler)}
*
* @param ctx
* @throws Exception
*/
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ChannelPipeline pipeline = ctx.pipeline();
System.out.println("MyHttpServerHandler.channelRegistered");
super.channelRegistered(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("MyHttpServerHandler.channelRead");
super.channelRead(ctx, msg);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("MyHttpServerHandler.channelInactive");
super.channelInactive(ctx);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("MyHttpServerHandler.channelReadComplete");
super.channelReadComplete(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("MyHttpServerHandler.channelUnregistered");
super.channelUnregistered(ctx);
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
System.out.println("MyHttpServerHandler.channelWritabilityChanged");
super.channelWritabilityChanged(ctx);
}
}
重启服务,curl访问: curl “http://localhost:8899” ,控制台输出如下:
MyHttpServerHandler.channelRegistered
MyHttpServerHandler.channelActive
MyHttpServerHandler.channelRead
执行channelRead0
MyHttpServerHandler.channelRead
MyHttpServerHandler.channelReadComplete
MyHttpServerHandler.channelReadComplete
MyHttpServerHandler.channelInactive
MyHttpServerHandler.channelUnregistered
结果很意外,channelRead执行了两次,channelReadComplete执行了两次。
后续会继续分析执行流程。