步骤:
- 一个服务端的
Handler
:用于处理连接创建后和接收到信息后的业务,构建一个FullHttpResponse
对象输出。 Server
:配置服务器的启动代码
也就是说我们只需要写一个处理者程序,然后写一个配置启动服务的 main 程序就可以构建一个 Web 服务了。
引入 Netty
我这里是使用 Maven
构建项目,当然你也可以通过下载引入 Jar 包的方式来构建
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.27.Final</version>
</dependency>
代码清单
- Handler.java
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
// @Sharable 标识这类的实例之间可以在 channel 里面共享
@Sharable
public class Handler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(msg instanceof HttpRequest) {
DefaultHttpRequest req = (DefaultHttpRequest) msg;
// 输出 request
System.out.println(req.toString());
}
String ret = "Hello Netty!";
// 将所接收的消息返回给发送者(输出)。注意,这还没有冲刷数据
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.wrappedBuffer(ret.getBytes()));
response.headers().set("content-type", "text/html");
response.headers().set("content-length",
response.content().readableBytes());
ctx.write(response);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// 冲刷所有待审消息到远程节点。关闭通道后,操作完成
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
// 关闭通道
ctx.close();
}
}
- server.java
import java.net.InetSocketAddress;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
public class Server {
private static final int port = 3000; // 监听端口
public static void main(String[] args) throws Exception {
NioEventLoopGroup group = new NioEventLoopGroup(); // 创建 EventLoopGroup
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group) // 创建 ServerBootstrap
.channel(NioServerSocketChannel.class) // 制定使用 NIO 的传输 Channel
.localAddress(new InetSocketAddress(port)) // 设置端口
.childHandler(new ChannelInitializer<SocketChannel>() {
// 将我们的 Handler 添加到 ChannelPipeline
@Override
public void initChannel(SocketChannel ch) throws Exception {
// server端发送的是httpResponse,所以要使用HttpResponseEncoder进行编码
ch.pipeline().addLast(new HttpResponseEncoder());
// server端接收到的是httpRequest,所以要使用HttpRequestDecoder进行解码
ch.pipeline().addLast(new HttpRequestDecoder());
ch.pipeline().addLast(new Handler());
}
});
ChannelFuture f = b.bind().sync(); // 绑定的服务器,sync() 等待服务关闭
System.out.println("Server started and listen on " + f.channel().localAddress());
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync(); // 关闭 EventLoopGroup
}
}
}
启动 Server
控制台输出
Server started and listen on /0:0:0:0:0:0:0:0:3000
浏览器访问 127.0.0.1:3000
Hello Netty!