[lab] csapp-proxy
proxy lab
這個lab的解決方案還是相對直觀的. 要求實現一個帶記憶體快取功能的http代理.
功能可以拆解為
- server
- client
- cache
一開始還有些疑惑, proxy server 只接受一個埠引數, 那如何知道轉發給誰呢? 看到測試指令碼使用 curl 才明白, 經過 --proxy 引數後, 雖然請求的目的地(包括第一行的uri 與 Host 頭資訊)還是 http server s, 但請求是發給 proxy server p 的.
大體的請求流程如下
沒有proxy c <--> s proxy 邏輯上請求 c ------- s \ / \ / \ / p
並且雖然 lab 要求中需要處理很多error case, 但實際給出 test case 並沒有覆蓋到, 再加上附帶 tiny server 的例子, 如果只是追求過lab, 直接使用 csapp 裡的 rio 等輔助函式就好.
proxy server
這裡涉及到網路程式設計相關知識, 簡要給出階段1的骨幹程式碼.
int main() { listen = Open_listenfd(); // 迴圈接受請求 while (client = accept(listen)) { handle_request(client); } } // 處理一次請求 int handle_request(client) { rio_t rio; http_header_map header_map; // 讀取第一行 read_line(client, buf); // method uri version // 解析 http 頭 header_map = read_headers(client); // 根據要求, 對一些 http header 進行修改 rewrite_headers(header_map); // 開啟請求的tcp client req_client = open_client(host); // 向其傳送 http 頭 send_header(req_client, header_map); // 對兩個 socket 的資料進行復制. proxy_content(req_client, client); }
這裡我使用了自定義型別 http_header_map 用來吧所有 header 存起來統一處理, 也可以直接開啟 http client, 處理完線上傳送.
如果是存起來要注意 字串的生命週期問題, 因為資料是存在本地buf中, 後面再讀取buf就被覆蓋了, 因此我們要malloc出來, 再拷貝.
其次是 uri 的解析, 雖然邏輯直觀, c語言寫起來還是挺麻煩的.
多執行緒
多執行緒要注意的問題還是 buf 的問題, 避免使用全域性緩衝區, 使用函式本地快取或與請求fd繫結就可以.
pthread_t thread; Pthread_create(&thread, NULL, (void *(*)(void *))handle_request, (void *)connfd); Pthread_detach(thread);
cache
cache 部分不要求我們完全按照http標準來控制, 算是簡化了許多.
首先實現一個支援 lru的 cache struct, lru 其實已經在 cache lib 中實現過了, 這裡不再贅述, 新增上快取大小檢查的程式碼即可.
然後是多執行緒訪問 cache, 這裡也使用最簡單的 pthread_rwlock_t 來控制, 在 set 里加寫鎖, get 裡先加讀鎖, 後加寫鎖更新訪問時間.
最後是應用 cache, 邏輯如下
handle_request() {
// 解析請求
// 如果存在 cache, 就直接使用 cache 來響應.
if (cache_item = cache_hit(uri)) {
cache_serve(cache_item)
return
}
// 否則建立新的 cache item 來儲存結果,
cache_item = create_cache_item();
client_serve(cache_item)
// 寫入cache中.
cache_set(cache_item)
}