原文地址:http://adolgarev.blogspot.com/2013/12/lets-do-our-own-full-blown-http-server.html

Sometimes servlets just doesn't fit you, sometimes you need to support some protocols except HTTP, sometimes you need something really fast. Allow me to show you the Netty that can suit for these needs.

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. (http://netty.io/)

Netty has everything one needs for HTTP, thus web server on Netty is like a low hanging fruit.
First of all you need to understand what pipeline is, see Interface ChannelPipeline. Pipeline is like processing line where various ChannelHandlers convert input bytes into output. Pipeline corresponds one to one to connection, thus ChannelHandlers in our case will convert HTTP Request into HTTP Response, handlers will be responsible for such auxiliary things like parsing incoming packets and assembling outcoming and also call business logic to handle requests and produce responses.
Full source is available.

There are 2 types of handlers.

  1. ChannelInboundHandlers that process incoming data.

  2. ChannelOutboundHandlers that produce data to be sent.

See How an event flows in a pipeline.
In our case we'll create following inbound handlers

--(ByteBuf)--> HttpRequestDecoder --(HttpObject)--> HttpObjectAggregator --(FullHttpRequest)--> RequestDecoder* --(Request*)--> FormPayloadDecoder* --(FullDecodedRequest*)--> DefaultHandler* --(Response*)--> DefaultExceptionHandler*

In braces you see messages being passed between handlers. With * marked our custom classes, all others are from Netty.

  • HttpRequestDecoder is responsible for low level parsing and converts raw bytes into HttpObject that correspond to HTTP request header and body chunks.

  • HttpObjectAggregator composes from these objects one single FullHttpRequest per HTTP request. It can be configured with maxContentLength to prevent too big requests.

  • RequestDecoder simply wraps FullHttpRequest into custom Request and adds auxiliary parameters namely orderNumber. HTTP client can send multiple requests in one connection and it expects responses in the same order. We process those requests in parallel and for instance second one can be processed before first. Thus we need to assembly responses in the right order before sending them out. For this purpose we assign index number to each incoming Request in our pipeline.

Example. Imagine to process request we just sleep specified amount of seconds.

telnet localhost 9999
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /?duration=5 HTTP/1.1 <-- sleep for 5 seconds
User-Agent: curl/7.33.0
Host: localhost:9999
Accept: */* GET /?duration=3 HTTP/1.1 <-- sleep for 3 seconds
User-Agent: curl/7.33.0
Host: localhost:9999
Accept: */* HTTP/1.1 200 OK <-- despite second request processed first we get both responses in the right order after 5 seconds
Content-Type: application/json
Content-Length: 18
Set-Cookie: JSESSIOINID=e9ma1foeretnh19u4demqta7tr
Connection: keep-alive "Slept for 5 secs"HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 18
Set-Cookie: JSESSIOINID=8ti5pbfc0dmd4r09i6or005r6b
Connection: keep-alive "Slept for 3 secs"
  • FormPayloadDecoder implements incoming parameters parsing. It uses QueryStringDecoder and HttpPostRequestDecoder from netty to parse application/x-www-form-urlencoded and multipart/form-data encoded GET and POST data. It produces FullDecodedRequest that differs from Request by containing Values - simple key-value mapping for parameter names and values. You can easily replace FormPayloadDecoder with any other handler that converts Request into FullDecodedRequest, for instance, parse JSON encoded data in POST body.

Sidenote. 'Why we cannot just update Request object like Request.setValues() and pass it further?' you say. There is a good reason to keep messages being passed immutable in multithreaded application (even though a connection is bound to particular thread in netty). Even more, type gives you an information about what you actually have. FullDecodedRequest clearly says that parameters were parsed, in case we make Request object mutable and set there Values one cannot say at any given point in time whether Request already contains Values or not. DefaultHandler in its turn requires FullDecodedRequest as input, in other words it says give me fully parsed request object with parameters. In case of mutable Request this restriction is not clear.

  • DefaultHandler uses a separate set of threads to handle business logic. It uses netty EventExecutorGroup that is like ExecutorService in Java SE. EventExecutorGroup provides methods to submit tasks and returns futures to observe (in contrast to Java SE Future one can add listeners to netty Future). Provider below is a callable that given input parameters produces some output object.

protected void channelRead0(final ChannelHandlerContext ctx,
  final FullDecodedRequest decodedRequest) throws Exception {
 Callable<? extends Object> callable = new Provider(
   decodedRequest.getPath(), decodedRequest.getValues());  final Future<? extends Object> future = executor.submit(callable);  future.addListener(new GenericFutureListener<Future<Object>>() {
  @Override
  public void operationComplete(Future<Object> future)
    throws Exception {
   if (future.isSuccess()) {
    ctx.writeAndFlush(new Response(decodedRequest.getRequest(),
      future.get()));
   } else {
    ctx.fireExceptionCaught(future.cause());
   }
  }
 });
}
  • DefaultExceptionHandler is a catch all handler that receives all exceptions from any handler above, makes pretty output from java stack trace and closes connection.

Now, given a result object, one need to produce output in HTTP way. For this purpose following outbound handlers are used.

--(Response*)--> JacksonJsonResponseEncoder* --(FullEncodedResponse*)--> ResponseEncoder* --(FullHttpResponse)--> HttpResponseEncoder --(ByteBuf)-->
  • Response contains result and reference to request. JacksonJsonResponseEncoder as you may guess uses Jackson library to convert response to JSON, produces FullEncodedResponse that contains FullHttpResponse with appropriate Content-Type and Content-Length set. You can replace JacksonJsonResponseEncoder with any other way to encode response, for instance, to xml or depending to Accept-Encoding request header.

Sidenote about the naming. If you have some interface lets say example.Showable don't call it example.IShowable or example.ShowableI (find out by yourself why). Also do not call implementations of this interface like example.ShowableImpl or example.impl.Showable. Concrete implementation of the interface must be specific in something that differs it from all other implementations (if there is only one implementation you are trying to trick yourself that you are loosely coupled). Reflect its specifics in its name like example.ShowableWhiteBoard, example.ShowablePixelBitmap.

  • ResponseEncoder evicts FullHttpResponse from FullEncodedResponse and handles such aspects as cookies, session ids, keep-alive, etc. Also it assembles responses in the right order.

  • HttpResponseEncoder is a netty thing that obviously produces raw bytes from FullHttpResponse. Pay attention at ReferenceCountUtil.release(httpRequest). Netty uses pool of buffers and reference counting to omit problems with GC. See Reference counted objects.

All those handlers are composed together into pipeline by DefaultServerInitializer. Feel free to browse the source code. Also take a look at various handlers from the box that you may find useful like HttpContentCompressor or SslHandler.

Let's do our own full blown HTTP server with Netty--转载的更多相关文章

  1. 758B Blown Garland

    B. Blown Garland time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  2. Codeforces758B Blown Garland 2017-01-20 10:19 87人阅读 评论(0) 收藏

    B. Blown Garland time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  3. B. Blown Garland

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  4. 【codeforces 758B】Blown Garland

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  5. Codeforces 758B Blown Garland

    题目链接:http://codeforces.com/contest/758/problem/B 题意:一个原先为4色环的链子少了部分,要你找出死的最少的一种可能,各输出四种颜色的死了多少. 分析:就 ...

  6. Codeforces 758B:Blown Garland(模拟)

    http://codeforces.com/problemset/problem/758/B 题意:给出一个字符串,每4个位置对应一个颜色,如果为‘!’的话,代表该灯泡是坏的,问最后每个颜色坏的灯泡的 ...

  7. Codeforces 392 B Blown Garland

    题意:输入是由连续的RYGB和字符!组成的字符串,R代表红灯,Y代表黄灯,G代表绿灯,B代表蓝灯.简而言之,就是给定的字符串保证了下标对4取余相同的灯颜色都相同,但是有的地方为‘!’代表这个灯坏了,然 ...

  8. Essential controls for web app

    AUTO-COMPLETE/AUTO-SUGGEST Auto-complete using Vaadin Offer auto-suggest or auto-complete to help yo ...

  9. Bible

    001 Love your neighbor as yourself.         要爱人如己.--<旧·利>19:18      002 Resentment kills a foo ...

随机推荐

  1. 120.VS调试技巧

    设置断点调试 在一行代码的左侧点击即可设置断点,按F5(调试->开始调试)即可运行到第一个端点处暂停 逐语句调试 按F11(调试->逐语句)即可开始一步一步执行 逐过程调试 按F10(调试 ...

  2. Zabbix + Grafana

    Grafana 简介 Grafana自身并不存储数据,数据从其它地方获取.需要配置数据源 Grafana支持从Zabbix中获取数据 Grafana优化了图形的展现,可以用来做监控大屏 Grafana ...

  3. 【IOS学习】1.第一个IOS程序

    1.执行原理 a.首先执行main函数 调用UIApplicationMain方法 return UIApplicationMain(argc, argv, nil, NSStringFromClas ...

  4. javafx Hanoi

    Netbean  java8    source code  :http://files.cnblogs.com/files/rojas/HNT.zip screenshot: 1  model /* ...

  5. 初识Oracle中的正则表达式

    Oracle使用正则表达式离不开这4个函数: 1.regexp_like 2.regexp_substr 3.regexp_instr 4.regexp_replace  

  6. POJ——T 3461 Oulipo

    http://poj.org/problem?id=3461 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 42698   ...

  7. 洛谷——P2590 [ZJOI2008]树的统计

    https://www.luogu.org/problem/show?pid=2590#sub 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这 ...

  8. 去掉“此电脑”中的“WPS云文档”图标

    平台:Win10 问题:安装了WPS2019专业版后,此电脑窗口出现了一个WPS云文档图标,无法删除,云文档设置中也无法取消. 解决:打开注册表,定位到HKEY_CURRENT_USER\Softwa ...

  9. JavaScript--数据结构之栈

    4.1栈是一种高效的数据结构,是一种特殊的列表.栈内元素只能通过列表的一端访问,也就称为栈顶.后入的先出的操作.Last in First out.所以他的访问每次是访问到栈顶的元素,要想访问其余的元 ...

  10. BZOJ2434: [Noi2011]阿狸的打字机(fail树+dfs序)

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...