# [2020q1](http://wiki.csie.ncku.edu.tw/linux/schedule) 第 11 週測驗題 ###### tags: `linux2020` :::info 目的: 檢驗學員對 Linux 記憶體管理、POSIX shared memory, POSIX semaphore 和 split/epoll 系統呼叫的認知 ::: ==[作答表單](https://docs.google.com/forms/d/e/1FAIpQLSe_Ka_m1O9oj0KjULO3VpXBDnsU2c4eliFJxtJQ_HF58X7tiA/viewform)== --- ### 測驗 `1` 考慮一個使用 POSIX shared memory 和 semaphore 開發的 [key-value store](https://en.wikipedia.org/wiki/Key-value_database) 實作,測試程式碼: ```cpp static void sig_handler(int dummy) { kv_delete_db(); exit(0); } int main() { signal(SIGINT, sig_handler); signal(SIGQUIT, sig_handler); signal(SIGTSTP, sig_handler); // Check create kv_store_create("/STORE"); // Check write kv_store_write("MyKey", "content [A]"); kv_store_write("MyKey", "content [B]"); for (size_t k = 0; k < 17; k++) { char str[5]; sprintf(str, "[%zu]", k); kv_store_write("MyKey", str); } for (int i = 0;; i++) { char *p = kv_store_read("MyKey"); if (!p) break; free(p); } // Check read_all char **v = kv_store_read_all("MyKey"); for (size_t i = 0; v[i]; i++) { printf("%zu => '%s'\n", i, v[i]); free(v[i]); } free(v); // Check destroy kv_store_destroy("/STORE"); return 0; } ``` 參考執行輸出: ``` 0 => 'content [A]' 1 => 'content [B]' 2 => '[0]' 3 => '[1]' 4 => '[2]' 5 => '[3]' 6 => '[4]' 7 => '[5]' 8 => '[6]' 9 => '[7]' 10 => '[8]' 11 => '[9]' 12 => '[10]' 13 => '[11]' 14 => '[12]' 15 => '[13]' 16 => '[14]' 17 => '[15]' 18 => '[16]' ``` 原始程式碼可見 [kv.c](https://gist.github.com/jserv/9db8ca1fe174a99eaccbfaebbf47b2bb)。 這份實作應該能在 multi-process 和 multi-thread 環境運作。 請補完上述 `kv.c` 程式碼。 ==作答區== AAA = ? * `(a)` `open` * `(b)` `shm_open` BBB = ? * `(a)` `store->clients` * `(b)` `store->clients++` * `(c)` `++store->clients` * `(d)` `store->clients--` * `(e)` `--store->clients` CCC = ? * `(a)` 0 * `(b)` `cache_idx` * `(c)` `cache_idx++` * `(d)` `cache_idx--` DDD = ? * `(a)` 0 * `(b)` `cache_idx` * `(c)` `cache_idx++` * `(d)` `cache_idx--` :::success 延伸問題: 1. 解釋上述程式碼運作原理,指出實作缺陷並改進 2. 設計實驗並探討改進存取效率的手法 ::: --- ### 測驗 `2` 以下程式碼嘗試透過 epoll 和 splice 系統呼叫,實作出具體而微的 [Port forwarding](https://en.wikipedia.org/wiki/Port_forwarding)。考慮一個情境:我們對外有一台防火牆,在 DNS 設定方面,我們設定 `ftp.mydomain.com` 及 `www.mydomain.com` 都指向這台防火牆。但我們希望所有 HTTP 連線都重新導向到內部的 `192.168.0.2` 這台機器上,而所有 FTP 連線都交由 `192.168.0.3` 來處理。這時候我們就可以使用 port forwarding 的方式來達成。對應的 NAT (Network Address Translation) 的設定如下: ```= redirect_port tcp 192.168.0.2:80 80 redirect_port tcp 192.168.0.3:20 20 redirect_port tcp 192.168.0.3:21 21 ``` 第一行的目的就是將 port 80 的 tcp 連線重新導向到 `192.168.0.2` 的 port 80,而第 2 和第 3 行是將 port 20 及 port 21 的連線交由 `192.168.0.3` 來處理。在 1`92.168.0.2` 及 `192.168.0.3` 這二台機器上,我們只要設定它們的 gateway 為防火牆的 IP,例如 `192.168.0.1` 即可。 使用 splice 系統呼叫,我們有機會在網路介面控制器的支援下,達到 Zero-copy 資料傳輸。 原始程式碼可見 [proxy.c](https://gist.github.com/jserv/99ad84d0b9ef8a5836cf93fc42b4f435),其 `list.h` 取自 [list.h](https://github.com/sysprog21/linux-list/blob/master/include/list.h),改寫自 Linux 核心原始程式碼。 假設本地機器系統 port 80 已有網頁伺服器在等待連線。`proxy` 的測試方式為 ```shell $ ./proxy 8082 localhost 80 ``` 等程式執行後,在另一個終端機畫面中輸入下列命令: ```shell $ telnet localhost 8082 ``` 接著你就可以輸入 HTTP 請求字串,如 `GET /index.html`。 此外,你還可以把 port 8082 轉向到 Google 首頁: 先找出 `www.google.com` 的 IP 地址: ```shell $ nslookup www.google.com ``` 得到以下輸出: ``` Name: www.google.com Address: 216.58.200.228 ``` 修改上述命令: ```shell ./proxy 8082 216.58.200.228 80 ``` 重複上述 `telnet` 命令,這時候就會看到 Google 首頁的字串。 請補完程式碼。 ==作答區== EEE = ? * `(a)` `num_events` * `(b)` `num_events++` * `(c)` `num_events--` * `(d)` `++num_events` * `(e)` `--num_events` FFF = ? * `(a)` 不需要加入程式碼 * `(b)` `buf->bytes += n` * `(c)` `buf->bytes -= n` * `(d)` `buf->bytes--` * `(e)` `buf->bytes++` :::success 延伸問題: 1. 解釋上述程式碼運作原理,指出實作缺陷並改進 2. 將 DNS 解析的機制納入,允許用 [FQDN](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) 作為輸入 3. 嘗試克服連線數量的限制,設計實驗並探討如此 port forwarding 的效率 :::
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.