主講人: jserv / 課程討論區: 2025 年系統軟體課程
返回「Linux 核心設計」課程進度表Image Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
接下來,我們思考同時處理命令列輸入與網頁伺服器,先找出程式等待輸入時的主要迴圈,位於 linenoise()->line_raw()->line_edit()
內的 while(1)
。但 linenoise 是用 read
等待使用者輸入,當 read 阻塞時,便無法接收 web 傳來的資訊。
嘗試用 select()
同時處理 stdin 及 socket:
line_edit
中加入以下程式碼:select
及 poll
皆使用此種 Model,好處是可以同時檢查多個 descriptor,但缺點是需要兩次的 system call,從圖中也可以看到,先透過 select
system call 呼叫到 kernel space 內等待資料,接著 kernel 接收到資料後通知 user space,再重新發送 recvfrom
system call 至 kernel space,意味著需要多次 context switch,成本相對比其他 Model (如 Blocking I/O) 來得高。
嘗試修改 console.c
,讓程式讀到 web
命令後手動按下 Enter 鍵繼續:
run_console()
:process()
處理 URL 字串並將 function name 與 parameter 以跟 cmdline
一樣的格式回傳 ([function name][space][parameter]
):在分析完 console.c
後,發現使用 cmd_select()
能夠滿足需求:
linenoise
API 才能達成,在輸入 web
命令後將 linenoise
關閉,並儲存監聽的 file descriptor:run_console()
依照 linenoise
開啟與否來選擇要使用 linenoise()
還是 cmd_select()
cmd_select()
新增對應的處理在 process()
中處理 http 請求與對應的狀態碼,與上方 process()
相同。
執行結果
根據 I'm getting favicon.ico error 描述,在 <head>
欄位中增加可讀取圖示位址的程式碼 <link rel="shortcut icon" href="#"
即可。此原因是因為某些網頁瀏覽器 (如 Chrome 瀏覽器) 會要求給予網頁圖案的需求,而原本提供的 head request 中沒有對應的資訊,故瀏覽器不會回傳正確的內容,而是一直提示要求給予 favicon.ico
檔案位置。
上述程式碼已整合進 qtest
,可在終端機執行以下命令:
如訊息所示,這個小型的網頁伺服器正在等待埠號 9999
的網路連線。 接著開啟另一個終端機,用 curl
命令進行連線,測試命令如下:
favicon.ico
的問題從瀏覽器發 request 後,可以看到上圖 favicon.ico 的 status 是 404。因為部分瀏覽器會要求 request 中要提供網頁圖案的對應資訊,而我上面的 response 沒有提供。
在 I'm getting favicon.ico error 有提供做法,就是將下面這行加進去 head 裡面即可:
因此修改 send_response()
,將上面的程式加進去:
再次嘗試,就都是 200 OK 了!
準備以下程式碼: (檔名: testweb.c
)
更改 bench.c,傳送 HTTP request 給開著的 web server,並接收 HTTP response,查看是否與預期的結果相同。
在 testweb.c
中,傳送 new 的命令,但是回傳回來除了執行結果還多了換行和一個隨機的字元…
因為原本的 web 實作中,HTTP 的 body 只會回傳 ok,現在要將原本輸出到標準輸出的結果也當作 HTTP response 傳回給 client。
在 qtest.c
的 do_operation 系列的函式,常常呼叫 report.c 的 report
和 report_noreturn
,為了將執行結果輸出到標準輸出,其中兩者差別在是否有輸出換行,輸出後有需要換行就會呼叫 report
,不需要會呼叫 report_noreturn
。
在 report
和 report_noreturn
檢查是否有連線,如果有連線,就將結果一起寫進 response 中,如此一來即可回傳執行結果。