# 於 Linux 上撰寫 daemon server 要注意的

要撰寫一個網路伺服器 Deamon，一般要注意掌控 fork() 所產生的子行程 (child process) 數目，因此程式中需要記錄以對子行程的數目進行限制，以預防有人惡意的不斷送出僅設有 SYN flag 的 TCP SYN 封包(packet)，導致 TCP 三向交握(Three-way handshaking)無法正常完成，而 Daemon 只能不斷停留在等待 SYN-ACK，最後耗盡系統資源，導致系統完全當機(crash)。\
\
ulimit -Ha 與 ulimit -Sa 來檢視目前系統的硬限制(Hard limit)與軟限制(Soft limit) 的值：

> \# ulimit -Sa\
> core file size (blocks, -c) 0\
> data seg size (kbytes, -d) unlimited\
> file size (blocks, -f) unlimited\
> max locked memory (kbytes, -l) unlimited\
> max memory size (kbytes, -m) unlimited\
> open files (-n) 1024\
> pipe size (512 bytes, -p) 8\
> stack size (kbytes, -s) 8192\
> cpu time (seconds, -t) unlimited\
> max user processes (-u) unlimited\
> virtual memory (kbytes, -v) unlimited\
> \
> \# ulimit -Ha\
> core file size (blocks, -c) unlimited\
> data seg size (kbytes, -d) unlimited\
> file size (blocks, -f) unlimited\
> max locked memory (kbytes, -l) unlimited\
> max memory size (kbytes, -m) unlimited\
> open files (-n) 1024\
> pipe size (512 bytes, -p) 8\
> stack size (kbytes, -s) unlimited\
> cpu time (seconds, -t) unlimited\
> max user processes (-u) unlimited\
> virtual memory (kbytes, -v) unlimited<br>

\
根據 man bash 對 ulimit hard limit 與 soft limit 的描述，他們的功用在於，hard limit 一旦設定之後就無法在增加該參數的值，而 soft limit 則是最多可以增加到與 hard limit 的值一樣多，還有就是 hard limit 是需要管理員權限(super user)才能更動的。\
\
像上例，就有個很明顯的 open files，這個項目的值就表示 Linux 預設一個行程可開啟的 file descriptor 數目是 1024 個，如果我們沒有更改這個值，那我們的程式最多只能開啟 1024 個檔案而已。\
\
除了檔案，由於 Linux 中開啟某裝置都是抽象化分層了，於是像開啟某個檔案一般，開啟的 socket 連線數也是受制於檔案的開啟數目，所以如果要讓 server 可以接受大於 1024 的連線，則需要修改這個值。\
\
有幾個系統呼叫 (system call)，可以寫在程式中更動這些預設值：\
\
ulimit()、getrlimit()/setrlimit()，其中後兩者是用來取代 ulimit() 的。\
\
下列是 getrlimit/setrlimit 系統呼叫的函式原型(prototype)：

> int getrlimit(int resource, struct rlimit);\
> int setrlimit(int resource, const struct rlimit \*rlim);<br>

\
其中 resource 是所要更動的項目選項，如我們想更動可開啟檔案的個數，則可修改 RLIMIT\_NOFILE，如 setrlimit( RLIMIT\_NOFILE, \&rlim);\
\
Man manual for details:\
$ man 2 getrlimit\
$ man 2 setrlimit\
\
細節可參考 manual:\
$ man 2 getrlimit\
$ man 2 setrlimit\
\
下列為 rlimit 的 structure：\
struct rlimit{\
&#x20;   rlimit\_t rlimit\_cur; // Soft-limit\
&#x20;   rlimit\_t rlim\_max; // Hard-limit\
};\
\
下面用一個簡單的範例，來呈現如何使用 getrlimit/setrlimit 取得與設定，這個範例，首先會用 getrlimit 取得目前可開啟檔案的 soft limit 與 hard limit，然後，再用 setrlimit 設定希望的值，最後再用 getrlimit 重新取得一次確認修改結果。

```c
// test.cpp
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <iostream>

using namespace std;

int main(void)
{
  struct rlimit limit;
  const struct rlimit mit = { 2048, 600000 };

  getrlimit(RLIMIT_NOFILE, &limit);
  cout << "Current: " << limit.rlim_cur << endl;
  cout << "Max: " << limit.rlim_max << endl;

  setrlimit(RLIMIT_NOFILE, &mit);

  getrlimit(RLIMIT_NOFILE, &limit);
  cout << "Current: " << limit.rlim_cur << endl;
  cout << "Max: " << limit.rlim_max << endl;

  return 0;
}
```

\
編譯:&#x20;

> g++ test.cpp -o test<br>

\
執行結果：

> \# ./test\
> Current: 1024\
> Max: 1024\
> Current: 2048\
> Max: 600000<br>

\
除了 RLIMIT\_NOFILE，其他還有如 RLIMIT\_NPROC (最大行程數目)、RLIMIT\_FSIZE (最大檔案大小)等都是需要注意的項目，關於 resource 的完整選項可以在 Linux /usr/include/bits/resource.h 找到。\
\
還有一個可查詢目前系統限制的函式，sysconf(int name)\
\
比如可以使用 sysconf( \_SC\_OPEN\_MAX ) 來查詢目前可開啟的最大檔案個數，細節請 man 3 sysconf，完整的參數有上百個，一樣是可以在 /usr/include/bits/confname.h 找到。\
\
Client 的部份則是要注意 connect timeout 問題，TCP sender 要注意 sned() 之傳回值，send 與 recv 可配合 select() 使用。\
\
PS: 設定 limit 雖然可以避免資源被耗盡，但是，該 sshd 服務等同於受到阻斷式攻擊，導致其他使用者無法連線，該怎麼辦呢?\
\
參考文獻：\
John Shapley Gray, [Interprocess Communications in Linux: The Nooks and Crannies](https://web.archive.org/web/20200306075425/http://www.amazon.com/gp/product/0130460427/ref=as_li_tf_tl?ie=UTF8\&camp=1789\&creative=9325\&creativeASIN=0130460427\&linkCode=as2\&tag=apla0fb9-20), Chap 2.9, Pearson Education, 2003.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://applezulab.netdpi.net/linux-prog/note-for-design-daemon.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
