Apache Bench でベンチマークできるミニマルな C 言語製 HTTP サーバ

ab コマンド, つまり Apache HTTP server benchmarking tool をつかってベンチマークできる状態の HTTP サーバを C 言語で作る. なるべくシンプルに必要最小限の要素のみを持ったコードを目指す. 手堅いエンジニアは高速化のために, いきなりコードを書いたりしない. 計測できる環境を整えておかないと, 高速化をしてもその効果を測ることができない. このサーバを出発点として手を加えて (例えばマルチスレッド化したり IO 多重化をしたりして) サーバのパフォーマンスがどのように変化するかを確かめるために使うことを想定している. ソースコード全体は https://github.com/momori256/cs2 にある. ソケット ab を使うには HTTP を解すサーバでなければならないため, まずは TCP での通信を実装する. ソケットプログラミングはお決まりのコードなので説明は省く. いつもお決まりを忘れてしまうので, man getaddrinfo の EXAMPLE をいつも参照している. socket, bind, listen をして accept できるソケットを作成する部分は以下の関数だ. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 int sock_create(const char* const port, int backlog) { typedef struct addrinfo addrinfo; addrinfo hints = {0}; { hints.ai_family = AF_INET; // IPv4. hints.ai_socktype = SOCK_STREAM; // TCP. hints.ai_flags = AI_PASSIVE; // Server. } addrinfo* head; { const int result = getaddrinfo(NULL, port, &hints, &head); if (result) { fprintf(stderr, "getaddrinfo. err[%s]\n", gai_strerror(result)); exit(1); } } int sfd = 0; for (addrinfo* p = head; p != NULL; p = p->ai_next) { sfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if (sfd == -1) { continue; } int val = 1; if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) { error("setsockopt"); } if (bind(sfd, p->ai_addr, p->ai_addrlen) == -1) { close(sfd); continue; } break; } freeaddrinfo(head); if (!sfd) { error("socket, bind"); } if (listen(sfd, backlog) == -1) { error("listen"); } return sfd; } HTTP リクエストとレスポンス accept して read すればメッセージを受信できる. 動作の確認には telnet のようなプリミティブなツールが役に立つ. ...

February 24, 2023 · 4 min