Netty程式設計——簡單的http伺服器
阿新 • • 發佈:2019-01-07
經常看到Tornado的監聽埠,身為Javaista,tomcat對底層封裝極其喪心病狂,計劃開始手擼一個基於Netty的http伺服器,並不斷完善,順便學習NIO和RPC
第一個超級簡單,hello world,本次編碼使用kotlin實現,具體和Java沒有太大區別,接下來從netty各個元件開始學習完善優化
- channel、eventloop和channelfuture
- netty資料容器
- 編解碼
- 多執行緒
- 網路協議
這樣粗淺低層次的POC正對應著本人水平~~package com.kotlin.server import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.close import io.netty.handler.codec.http.HttpRequest import io.netty.bootstrap.ServerBootstrap import io.netty.buffer.Unpooled import io.netty.channel.ChannelHandlerContext import io.netty.channel.ChannelInboundHandlerAdapter import io.netty.channel.ChannelInitializer import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.socket.nio.NioServerSocketChannel import java.io.UnsupportedEncodingException import io.netty.channel.socket.SocketChannel import io.netty.handler.codec.http.* object HttpServer { @Throws(InterruptedException::class) @JvmStatic fun main(args: Array<String>) { val bossGroup = NioEventLoopGroup() val workerGroup = NioEventLoopGroup() try { val b = ServerBootstrap() b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel::class.java) .childHandler(object : ChannelInitializer<SocketChannel>() { @Throws(Exception::class) override fun initChannel(ch: SocketChannel) { val pipeline = ch.pipeline() pipeline.addLast(HttpServerCodec()) pipeline.addLast(HttpServerHandler()) } }) val f = b.bind(8080).sync() f.channel().closeFuture().sync() } finally { workerGroup.shutdownGracefully() bossGroup.shutdownGracefully() } } } internal class HttpServerHandler : ChannelInboundHandlerAdapter() { @Throws(UnsupportedEncodingException::class) override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { if (msg is HttpRequest) { // 請求,解碼器將請求轉換成HttpRequest物件 // val request:HttpRequest = msg // 獲取請求引數 val queryStringDecoder = QueryStringDecoder(msg.uri()) var name = "World" // if (queryStringDecoder.parameters().get("name") != null) { // name = queryStringDecoder.parameters().get("name").get(0) // } // 響應HTML val responseHtml = "<html><body>Hello, $name</body></html>" val responseBytes = responseHtml.toByteArray(charset("UTF-8")) val contentLength = responseBytes.size // 構造FullHttpResponse物件,FullHttpResponse包含message body val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseBytes)) response.headers().set("Content-Type", "text/html; charset=utf-8") response.headers().set("Content-Length", Integer.toString(contentLength)) ctx.writeAndFlush(response) } } override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { cause.printStackTrace() ctx.close() } }