使用Netty实现HTTP服务器

关键字:使用Netty实现HTTP服务器,使用Netty实现httpserver,Netty Http server

Netty是一个异步事件驱动的网络应用程序框架用于快速开发可维护的高性能协议服务器和客户端。Netty经过精心设计,具有丰富的协议,如FTP,SMTP,HTTP以及各种二进制和基于文本的传统协议。

Java程序员在开发web应用的时候,截止2018年大多数公司采用的还是servlet规范的那一套来开发的,比如springmvc。虽然在2018年Java程序员们可以选择使用spring5中的webflux,但是这个转变没那么快。然而,基于servlet那一套的springmvc性能很差,如果你厌烦了,你大可以使用netty来实现一个web框架。假设你想使用netty来实现,那么第一步你得会使用Netty启动一个HTTP服务器,下面开始吧。

Netty系列的文章在这里https://www.cnblogs.com/demingblog/p/9912099.html

本文HttpServer的实现目标

本文只是为了演示如何使用Netty来实现一个HTTP服务器,如果要实现一个完整的,那将是十分复杂的。所以,我们只实现最基本的,请求-响应。具体来说是这样的:

1. 启动服务
2. 客户端访问服务器,如:http://localhost:8081/index
3. 服务器返回 : 你请求的uri为:/index

创建server

netty 的api设计非常好,具有通用性,几乎就是一个固定模式的感觉。server端的启动和客户端的启动代码十分相似。启动server的时候指定初始化器,在初始化器中,我们可以放一个一个的handler,而具体业务逻辑处理就是放在这一个个的handler中的。写好的server端代码如下:

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;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.net.InetSocketAddress;

/**
 * netty server
 * 2018/11/1.
 */
public class HttpServer {

    int port ;

    public HttpServer(int port){
        this.port = port;
    }

    public void start() throws Exception{
        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        bootstrap.group(boss,work)
                .handler(new LoggingHandler(LogLevel.DEBUG))
                .channel(NioServerSocketChannel.class)
                .childHandler(new HttpServerInitializer());

        ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
        System.out.println(" server start up on port : " + port);
        f.channel().closeFuture().sync();

    }

}

server端代码就这么多,看起来很长,但是这就是一个样板代码,你需要着重留意的就是childHandler(new HttpServerInitializer());这一行。如果你对netty还不是十分熟悉,那么你不需要着急把每一行的代码都看懂。这段代码翻译成可以理解的文字是这样的:

1.bootstrap为启动引导器。

2.指定了使用两个时间循环器。EventLoopGroup

3.指定使用Nio模式。(NioServerSocketChannel.class)

4.初始化器为HttpServerInitializer

server启动代码就是这么多,我们注意看 HttpServerInitializer 做了什么。

在HttpServerInitializer 中添加server配置

HttpServerInitializer 其实就是一个ChannelInitializer,在这里我们可以指定我们的handler。前面我们说过handler是用来承载我们具体逻辑实现代码的地方,我们需要在ChannelInitializer中加入我们的特殊实现。代码如下:

public class HttpServerInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast(new HttpServerCodec());// http 编解码
        pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024)); // http 消息聚合器                                                                     512*1024为接收的最大contentlength
        pipeline.addLast(new HttpRequestHandler());// 请求处理器

    }
}

上面代码很简单,需要解释的点如下:

1. channel 代表了一个socket.
2. ChannelPipeline 就是一个“羊肉串”,这个“羊肉串”里边的每一块羊肉就是一个 handler.
   handler分为两种,inbound handler,outbound handler 。顾名思义,分别处理 流入,流出。
3. HttpServerCodec 是 http消息的编解码器。
4. HttpObjectAggregator是Http消息聚合器,Aggregator这个单次就是“聚合,聚集”的意思。http消息在传输的过程中可能是一片片的消息片端,所以当服务器接收到的是一片片的时候,就需要HttpObjectAggregator来把它们聚合起来。
5. 接收到请求之后,你要做什么,准备怎么做,就在HttpRequestHandler中实现。

httpserver处理请求

上面的展示了 server端启动的代码,然后又展示了 server端初始化器的代码。下面我们来看看,请求处理的handler的代码:

public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx,FullHttpRequest req) throws Exception {
        //100 Continue
        if (is100ContinueExpected(req)) {
            ctx.write(new DefaultFullHttpResponse(
                           HttpVersion.HTTP_1_1,HttpResponseStatus.CONTINUE));
        }
		// 获取请求的uri
        String uri = req.uri();
        Map<String,String> resMap = new HashMap<>();
        resMap.put("method",req.method().name());
        resMap.put("uri",uri);
        String msg = "<html><head><title>test</title></head><body>你请求uri为:" + uri+"</body></html>";
       // 创建http响应
        FullHttpResponse response = new DefaultFullHttpResponse(
                                        HttpVersion.HTTP_1_1,HttpResponseStatus.OK,Unpooled.copiedBuffer(msg,CharsetUtil.UTF_8));
       // 设置头信息
        response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/html; charset=UTF-8");
        //response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain; charset=UTF-8");
       // 将html write到客户端
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}

上面代码的意思,我用注释标明了,逻辑很简单。无论是FullHttpResponse,还是 ctx.writeAndFlush都是netty的api,看名知意即可。半蒙半猜之下,也可以看明白这个handler其实是:1 .获取请求uri,2. 组装返回的响应内容,3. 响应对融到客户端。需要解释的是100 Continue的问题:

100 Continue含义
HTTP客户端程序有一个实体的主体部分要发送给服务器,但希望在发送之前查看下服务器是否会接受这个实体,所以在发送实体之前先发送了一个携带100 Continue的Expect请求首部的请求。
服务器在收到这样的请求后,应该用 100 Continue或一条错误码来进行响应。

启动Http服务器,演示效果

上面的代码写完了,看的再多,不如运行起来跑一把。上面的3个类已经包含了我们目标中的服务端的完整代码。我们只需要在main函数中将其启动即可,代码如下:

public class Application {

    public static void main(String[] args) throws Exception{
        HttpServer server = new HttpServer(8081);// 8081为启动端口
        server.start();
    }
}

运行这个main函数,在浏览器中访问:http://localhost:8081/indexhttp://localhost:8081/text/test 试试看吧。

至此,我们基于Netty的简易的Http服务器实现了(如果可以称作“HTTP服务器”的话)。 假如我们想要实现,访问 /index.html就返回index.html页面,访问/productList就返回“商品列表JSON”,那么我们还需要做请求路由,还要加入JSON序列化支持,还要根据不同的请求类型调整HTTP响应头。本篇就不做展开了,本篇的目标是为了试下一个最简单的Http服务器。源码下载

使用Netty实现HTTP服务器
Netty实现心跳机制
Netty开发redis客户端,Netty发送redis命令,netty解析redis消息
Netty系列

spring如何启动的?这里结合spring源码描述了启动过程
SpringMVC是怎么工作的,SpringMVC的工作原理
spring 异常处理。结合spring源码分析400异常处理流程及解决方法
Mybatis Mapper接口是如何找到实现类的-源码分析

alt 我的公众号

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Netty实现httpserver简单示例 3个Java类实现最基本的接收请求,响应一个文本的简单http服务器。 https://www.cnblogs.com/demingblog/p/99707
Java NIO系列1 概观 Java NIO。中间的N你既可以理解为(new),也就是新的IO,相对于java1.5之前的IO它确实是新的;也可以理解为(no blocking),也就是非阻塞的IO
关键字:使用Netty实现HTTP服务器,使用Netty实现httpserver,Netty Http server Netty是一个异步事件驱动的网络应用程序框架用于快速开发可维护的高性能协议服务器
netty心跳机制示例,使用Netty实现心跳机制,使用netty4,IdleStateHandler 实现。Netty心跳机制,netty心跳检测,netty,心跳 本文假设你已经了解了Netty的
关键字:Netty开发redis客户端,Netty发送redis命令,netty解析redis消息, netty redis ,redis RESP协议。redis客户端,netty redis协议
前提 最近一直在看Netty相关的内容,也在编写一个轻量级的RPC框架来练手,途中发现了Netty的源码有很多亮点,某些实现甚至可以用苛刻来形容。另外,Netty提供的工具类也是相当优秀,可以开箱即用
前言 最近在调研Netty的使用,在编写编码解码模块的时候遇到了一个中文字符串编码和解码异常的情况,后来发现是笔者犯了个低级错误。这里做一个小小的回顾。 错误重现 在设计Netty的自定义协议的时候,
我正在研究Netty应用程序.我想在不同的端口上运行多个服务器,如果没有(阻塞)closeFuture().sync(),它就无法工作. 我使用以下代码在ServerManager类中启动服务器: gpcmServer = new GpcmServer(port); gpspServer = new GpspServer(port); 在这些类中,我按如下方式启动服务器: public Gpsp
之前写了一篇文章:Java网络IO编程总结(BIO、NIO、AIO均含完整实例代码),介绍了如何使用Java原生IO支持进行网络编程,本文介绍一种更为简单的方式,即JavaNIO框架。
游戏一般是长连接,自定义协议,不用http协议,BIO,NIO,AIO这些我就不说了,自己查资料
netty处理客户端传过来的get、post、websocket数据例子
利用Netty中提供的HttpChunk简单实现文件传输
我正在为我的项目制作Netty原型.我试图在Netty上实现一个简单的面向文本/字符串的协议.在我的管道中,我使用以下内容: public class TextProtocolPipelineFactory implements ChannelPipelineFactory { @Override public ChannelPipeline getPipeline() throws Except
我是Netty的新手,我正在使用它来创建一个简单的http代理服务器,它接收来自客户端的请求,将请求转发给另一个服务器,然后将响应复制回原始请求的响应.一个额外的要求是我能够支持超时,因此如果代理服务器花费太长时间来响应,代理将自行响应并关闭与代理服务器的连接.我已经使用Jetty实现了这样的应用程序,但是使用Jetty我需要使用太多的线程来阻止入站请求被阻
对于我使用netty nio lib在 Java中开发的下载客户端,我还实现了带宽限制功能.从技术上讲,我是通过GlobalTrafficShapingHandler对象完成的.基于这个类’JavaDoc我初始化nio客户端管道如下: ... trafficHandler = new GlobalTrafficShapingHandler( new HashedWheelTimer
我正在使用Netty 4.1 Beta3构建一个消息传递应用程序来设计我的服务器,并且服务器理解MQTT协议. 这是我的MqttServer.java类,它设置Netty服务器并将其绑定到特定端口. EventLoopGroup bossPool=new NioEventLoopGroup(); EventLoopGroup workerPool=new NioEventLoopG
我在我的Apache服务器上设置了MOD_SPDY,现在想要改进我的客户端代码,使用Netty的SPDY实现通过SPDY通道将我的请求发送到服务器. 这是我第一次使用Netty的经历,所以我想我得到了我需要以某种方式配置我的频道,然后通过它发送请求.问题是,它似乎不清楚如何配置通道,甚至在此之后,如何跟踪可能同时执行的通道内的多个HTTP请求. 我用Google搜索并找到了SPDY包: http:
您好我有一个Netty Server,其处理程序应该接受字符串.它似乎只接收最多1024个字节的内容.如何增加缓冲区大小.我已经尝试过了 bootstrap.setOption("child.sendBufferSize", 1048576); bootstrap.setOption("child.receiveBufferSize", 1048576); 没有成功. 处理程序如下 public
我需要使客户端能够进行很多连接.我使用Netty 4.0.不幸的是,所有现有的示例都不显示如何创建大量的连接. public class TelnetClient { private Bootstrap b; public TelnetClient() { b = new Bootstrap(); } public void connect(Stri
根据Netty in Action v10的说法,引用计数用于处理ByteBuf的汇总.但是JVM不知道netty引用计数,所以JVM仍然可以使用ByteBuf.如果是这样,为什么还需要关心引用计数和手动调用release()方法? 我从书中引用了一些, Netty in Action v10>添加一些上下文. One of the tradeoffs of reference-counting