自己剛實現了一個輕量級的嵌入式http服務器,Java語言,基於nio。
同時提供類似spring mvc的功能, 包括@Controller,@RequestMapping,參數注入等功能。
項目地址:LightWebServer
項目總計1700行java代碼, {理解原理 + 不實現}三天左右,{理解原理 + 自己實現}需要一週左右。
下面分享一下自己的學習步驟:
1.學習nio相關知識
簡單來說nio是用來處理socket連接的,包括:
- 建立服務端和客戶端之間的連接
- 從socket讀數據(讀http request的數據)
- 往socket寫數據(寫http response的數據)
注:服務端監聽客戶端發起的連接請求。瀏覽器,postman插件,idea的TEST RESTful Web Service插件,自己寫的發送http請求的代碼等都可以看成客戶端。
nio學習路線:通道 -> 選擇器 -> 緩衝區(千萬不要按書中的順序一開始就學緩衝區API, 頭會暈的)。學完後用nio處理的這一部分完整代碼在這。目前沒有實現keep-alive,一個線程(選擇器所在線程)管理多個通道(nio核心理念)。讀取完一個請求後開一個線程(RequestHandler類)處理http請求。
public void read(SelectionKey key) throws IOException { SocketChannel client = (SocketChannel) key.channel(); ThreadPool.execute(new RequestHandler(client, selector)); key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);//目前一個請求對應一個socket連接,沒有實現keep-alive }
2.解析http請求(parse http request)
3.生成http響應(generate http response)
因爲需要做springmvc中類似@Controller和@RequestMapping功能,所以需要做以下兩件事
- 掃描所有被@Controller註解的類和該類中被@RequestMapping註解的方法
- 找到對應的方法去執行請求,方法返回com.light.http.responses.Response。
4.將響應寫回給客戶端
public void write(SelectionKey key) throws IOException { SocketChannel client = (SocketChannel) key.channel(); Response response = (Response) key.attachment();//從key中取出response ByteBuffer byteBuffer = response.getResponseBuffer(); if(byteBuffer.hasRemaining()){ client.write(byteBuffer); } if(!byteBuffer.hasRemaining()){ key.cancel(); client.close(); } }
References
- HTTP規範
- nio教程