概述
使用主从线程模型搭建服务器
- 构建一对主从线程组
- 定义服务器启动类
- 为服务器设置Channel(每一个客户端需要在服务端注册一个channel数据通道)
- 设置处理 从线程池 的助手类初始化器(处理子线程组助手类handler)
- 监听启动和关闭服务器
步骤
绑定8088端口,采用不指定路由的方式,即所有访问localhost:8088的路由都能返回Hello Netty(比如localhost:8088/test)
创建Maven项目,pom中添加依赖(<dependencies></dependencies>中)
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.37.Final</version>
</dependency>
主体类(含有main方法) HelloServer.java
package com.imooc.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @Author Sakura
* @Date 5/8/2019
* @Description 客户端发送一个请求,服务端返回Hello Netty
**/
public class HelloServer {
public static void main(String[] args) throws Exception {
//定义一对线程组
//主线程组,接收客户端连接
EventLoopGroup bossGroup = new NioEventLoopGroup();
//从线程组,处理事件
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//服务器创建,ServerBootstrap是启动类
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup) //设置主从线程组
.channel(NioServerSocketChannel.class) //设置NIO双向通道
.childHandler(new HelloServerInitialiizer()); //子处理器,处理workerGroup
//启动server,绑定8088端口,启动方式为同步
ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();
//监听关闭的channel,设置为同步方式
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
初始化器 HelloServerInitialiizer.java
package com.imooc.netty;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* @Author Sakura
* @Date 5/8/2019
* @Description 初始化器,channel注册后,执行相应初始化方法
**/
public class HelloServerInitialiizer extends ChannelInitializer<SocketChannel> {
protected void initChannel(SocketChannel socketChannel) throws Exception {
//通过socketChannel获得对应管道
ChannelPipeline channelPipeline = socketChannel.pipeline();
//通过管道,添加handler
//HttpServerCodec是由Netty 提供的助手类。请求来到服务端时解码,响应到客户端时编码
channelPipeline.addLast("HttpServerCodec",new HttpServerCodec());
//添加自定义助手类,返回"hello netty"
channelPipeline.addLast("customHandler",new CustomHandler());
}
}
返回Hello Netty的助手类 CustomHandler.java
package com.imooc.netty;
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;
/**
* @Author Sakura
* @Date 5/8/2019
* 创建自定义助手类
**/
//SimpleChannelInboundHandler:对于请求,相当于[入站]
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> {
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
//获取channel
Channel channel = channelHandlerContext.channel();
//仅处理HttpRequest请求
if(httpObject instanceof HttpRequest){
//显示客户端远程地址
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());
//把响应刷新到客户端
channelHandlerContext.writeAndFlush(response);
}
}
}
测试
启动项目后,浏览器输入localhost:8088
控制台显示
为什么显示两条那,打开请求网页的开发者工具,network栏目,刷新网页重新请求,发现有两条请求(下边的请求为图标请求)
可以使用命令行(cmd)进行纯净的请求
此时控制台只有一条