我这次是按照NIO模型编写的一个服务端
public class HelloServer {
public static void main(String[] args) throws Exception {
//定义一对线程组
//主线程组,用于接收客户端的连接,但是不做任何处理,跟老板一样,不做事
EventLoopGroup bossGroup=new NioEventLoopGroup();
//从线程组,老板线程组会把任务丢给她,让手下线程组去做任务
EventLoopGroup workerGroup=new NioEventLoopGroup();
try {
//netty服务器的创建,ServerBootstrap 是一个启动类
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup) //设置主从线程组
.channel(NioServerSocketChannel.class) //设置nio的双向通道
.childHandler(new HelloServerInitializer()); //子处理器,用于处理workerGroup
//启动server,并且设置8088为启动的端口号,同时启动方式为同步
ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();
//监听关闭的channel,设置位同步方式
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
复制代码
NIO模型中,服务端有两个线程组,一个线程组是用来完成客户端到服务端连接的,另一个线程组是用来处理IO操作的,通过ServerBootstrap这个类的实例绑定在一起。
//初始化器,channel注册后,会执行里面的相应的初始化方式
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
//通过Socketchannel去获取对应的管道
ChannelPipeline pipeline=channel.pipeline();
//通过管道
//HttpSeverCodec是由netty自己提供的助手类,可以理解为拦截器
//当请求到服务端,我们需要做解码,响应到客户端做编码
pipeline.addLast("HttpServerCodec",new HttpServerCodec());
//添加自定义的助手类,返回"hello netty~"
pipeline.addLast("customHandler",new CustomHandler());
}
}
复制代码
//创建自定义助手类
//SimpleChannelInboundHandler:对于请求来讲,相当于【入栈,出栈】
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject httpObject) throws Exception {
// 获取channel
Channel channel=ctx.channel();
if(httpObject instanceof HttpRequest){
// 显示客户端的远程地址
System.out.println(channel.remoteAddress());
// copiedBuffer在JVM中创建一块缓冲区适用于深拷贝缓冲区的
ByteBuf content= Unpooled.copiedBuffer("Hello chenhao~", 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);
}
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel...注册");
super.channelRegistered(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel...移除");
super.channelUnregistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel...活跃");
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel...不活跃");
super.channelInactive(ctx);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel读取完毕...");
super.channelReadComplete(ctx);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
System.out.println("channel用户事件触发...");
super.userEventTriggered(ctx, evt);
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
System.out.println("channel可写更改...");
super.channelWritabilityChanged(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("捕获到异常");
super.exceptionCaught(ctx, cause);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("助手类添加");
super.handlerAdded(ctx);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("助手类移除");
super.handlerRemoved(ctx);
}
}
复制代码