首先須要說明的是作這個小項目純粹出於學習目的,目前尚未多大的實用價值。只是以爲使用Lua和C結合來實現一個HTTP服務器的這種架構很是簡潔和易用,值得專門造一個輪子來深刻了解和學習這種用法,順便也實際動手體驗一下實現一個HTTP服務器的感受,固然裏面還有不少不完整或者說沒有考慮周全的地方:好比接收HTTP請求的時候默認了HTTP請求頭的全部數據都在一個數據包中一次性讀取完成,這在生產環境中確定不行(這個問題留着之後解決吧)。html
首先介紹一下這個HTTP服務器實現的功能:linux
實現這麼一個HTTP服務器能夠學習到的東西:數組
在lua/task_test.lua
文件中給出了Lua中註冊鉤子函數的示例程序,首先要加載libtask
這個庫,而後調用task.regExecutor("HTTPGET:/lua_hello.html", 0, callback)
來註冊鉤子函數,他的意思是假如你使用GET請求訪問這個連接http://server_ip/lua_hello.html
時會調用到Lua中的callback
函數。其中第二個參數0
表示這個鉤子函數的優先級,也就是說同一個URI能夠註冊多個鉤子函數來處理,而後服務器會按照這個優先級來依次調用註冊的鉤子函數。瀏覽器
註冊鉤子函數的功能是在libtask.c
這個文件中實現的,它的實質就是以URI爲哈希的Key,一個任務的結構體指針爲Value存儲在哈希表中(一個任務結構體就是一個鉤子函數執行時所須要的全部元素的集合)。由於須要支持一個URI能夠註冊多個鉤子函數因此每一個哈希槽中存儲的是一個鏈表頭,而後這個鏈表上按照優先級順序掛着這個URI註冊的全部任務。當HTTP請求到來時,以URI來查詢哈希表找到對應的鏈表,而後遍歷執行鏈表上的全部任務。如圖:
圖1. 原諒個人畫圖水平服務器
其中HTTP請求時的全部參數也所有解析爲鍵值對,存放在一個哈希表中,Lua中經過local param = task:getParam()
接口能夠獲取到參數的引用,而後調用param:get("User-Agent")
獲取到對於的值,其中lua/param_test.lua
文件中給出了使用示例。架構
Lua鉤子函數處理請求以後的返回數據經過調用task:replay(replay)
其中replay
參數組織爲一個table表,傳遞到C中而後合併爲一個返回請求,其中lua/return_test.lua
文件中給出了使用示例。異步
網上關於epoll、select分析的文章處處都是,在這裏就只記錄一些比較重要的地方:
關於select調用的幾個缺點:函數
而epoll克服了上述全部缺陷,他沒有最大數量的限制,它是經過一個專門的函數接口來增長或者刪除你須要監聽的句柄,因此沒必要每次都所有下發一邊,而且它接收到事件返回的時候也只是將當前就緒的句柄返回給用戶空間而不是全部句柄。其中epoll中須要關注的一點是它的兩種模式:LT模式與ET模式,它們之間的區別是:性能
epoll_wait
檢測到描述符事件發生並將此事件通知應用程序,應用程序能夠不當即處理該事件。下次調用epoll_wait
時,會再次響應應用程序並通知此事件。epoll_wait
檢測到描述符事件發生並將此事件通知應用程序,應用程序必須當即處理該事件。若是不處理,下次調用epoll_wait
時,不會再次響應應用程序並通知此事件。這兩種區別在內核中的實現參考這篇文章:Linux內核epoll ET/LT辨析
select
在內核中的實現參考這篇文章:Linux內核select源碼剖析
epoll、select之間的區別參考這篇文章:select、poll、epoll之間的區別總結[整理]學習
其中HTTP頭的解析是本身寫的一個很是簡陋的解析器,其中將URL中攜帶的參數和請求頭中的全部參數解析成key-value的形式,所有放在了一個哈希表中傳遞到Lua中,在Lua中能夠經過key來獲取參數值。Lua回調函數處理完成後的返回數據是經過一個table表傳遞到C語言中,而後經過這個表構造HTTP的返回頭部,返回給瀏覽器。固然這個HTTP服務器也能夠返回文件給瀏覽器,返回文件所有在C中作的,經過Linux的一個sendfile
系統調用實現異步發送數據到客戶端。
首先須要下載Lua5.2.4的源碼編譯安裝,另外我將Lua編譯爲一個動態庫放在了源碼目錄,程序執行時加載動態庫和其餘Lua庫同樣。我已經將所需的庫文件放在了源碼目錄,下載後直接make就行。