利用netty实现一个http服务器

主要分为五个步骤

  • 设置主从线程组
  • 设置服务器启动类
  • 为服务器设置channel
  • 设置启动类的助手类
  • 监听和关闭

接下来解释为什么会有这五步:

为什么设置主从线程组

放张图,讲述线程模型

为什么设置服务器启动类

这个服务器启动类,在我看来,相当于管理中心,他负责整体调度,和初始化设置,比如,我们之前创建了主从线程组,他要管理主从线程组,要不然,之前,创建的线程组,放在那里,怎么用,没人管啊!所以,服务器启动类要管理这些线程组。

为服务器设置channel

channel,可以理解为负责IO操作的组件。设置channel是为了说我建立一个什么样的channel,来处理这些请求(设置channel的这个地方,理解的不是很深刻,如果有大神了解的比较深入,请在评论解释一下哈)

设置启动类的助手类

助手类是说,好了请求来了,现在该怎么处理呢,那这就由助手类来决定了

监听和关闭

主要设置使用哪个端口,同步,还是异步。

好了,上代码

package com.example.netty.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;

/**
 * @ClassName HelloServer
 * @Description 实现客户端发送一个请求,服务器会返回hello netty
 * @Author miaoxu
 * @Date 2019/7/28 23:32
 * @Version 1.0
 **/
public class HelloServer {
    public static void main(String[] args) throws InterruptedException {
        //主线程组,接受客户端的链接,不做任何处理,和老板一样,不做任何事情
        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

            ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();

            //监听关闭的channel,设置位同步方式
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

package com.example.netty.netty;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;


/**
 * @ClassName HelloServerInitializer
 * @Description 初始化器,channel注册后,会执行里面的相应的初始化方法
 * @Author miaoxu
 * @Date 2019/7/28 23:46
 * @Version 1.0
 **/
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //通过SocketChannel获取对应的管道
        ChannelPipeline channelPipeline = socketChannel.pipeline();

        //通过管道,添加handler
        // HttpServerCodec是由netty自己添加的助手类,可以理解为拦截器
        // 当请求到服务端,我们需要做编码,相应到客户端做编码
        channelPipeline.addLast("", new HttpServerCodec());
        channelPipeline.addLast("customHandler", new CustomHandler());
    }
}

package com.example.netty.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.channel.internal.ChannelUtils;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

/**
 * @ClassName CustomHandler
 * @Description 创建自定义的助手类
 * @Author miaoxu
 * @Date 2019/7/28 23:53
 * @Version 1.0
 **/

//对于请求来讲,相当于入站,入境
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject>{
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        // 获取channel
        Channel channel = channelHandlerContext.channel();
        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);
        }





    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值