0Pricing
C++ Academy · レッスン

TCPエコーサーバーの構築

完全なTCPエコーサーバーの実装を順に学びます。

「TCPエコーサーバーの構築」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。

目標

接続を受け付け、バイト列を読み取り、それをそのまま書き戻す最小限のTCPサーバーを構築します。ネットワークプログラミングにおける「Hello World」です。

サーバーの基本構造

サーバーの処理の流れは、ソケットの作成、bind、listen、accept、処理です。これを永続的にループします。

int srv = socket(AF_INET, SOCK_STREAM, 0);
bind(srv, (sockaddr*)&addr, sizeof(addr));
listen(srv, 10);
while (true) {
    int client = accept(srv, nullptr, nullptr);
    handle(client);
    close(client);
}

アドレス再利用オプション

SO_REUSEADDRを設定すると、OSがポートを解放するのを待たずにサーバーをすぐ再起動できます。

int yes = 1;
setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

エコーループ

バッファーに読み込み、同じバイト列を書き戻します。クライアントが接続を閉じたら停止します。

void handle(int client) {
    char buf[1024];
    while (true) {
        ssize_t n = recv(client, buf, sizeof(buf), 0);
        if (n <= 0) break;          // closed or error
        send(client, buf, n, 0);
    }
}

部分読み取りと部分書き込み

recvとsendは、要求したバイト数より少ないバイト数しか転送しないことがあります。ストリームベースのプロトコルでは、完了するまでループしてください。

ssize_t total = 0;
while (total < n) {
    ssize_t s = send(client, buf + total, n - total, 0);
    if (s <= 0) break;
    total += s;
}

複数クライアントの処理

最も簡単な方法は、接続ごとに新しいスレッドを作成することです。数百クライアントなら機能しますが、数千クライアントでは処理が難しくなります。

while (true) {
    int client = accept(srv, nullptr, nullptr);
    std::thread([client]{ handle(client); close(client); }).detach();
}

より良い方法:スレッドプール

接続ごとにスレッドを生成すると、大規模環境ではリソースを浪費します。固定サイズのスレッドプールとワークキューを使うほうがスケールしやすくなります。

グレースフルシャットダウン

SIGTERMやSIGINTを処理して、リッスンソケットを適切にクローズします。RAIIを使うと、すべてのクライアントソケットも確実にクローズできます。

エラー処理

エラーは想定されるものとして扱ってください。クライアントは切断し、ネットワークは一時的に不調になり、OSのリソース上限に達することがあります。ログを記録して処理を続け、問題のあるクライアントだけでクラッシュしないようにします。

各クライアントのロギング

可観測性を確保するため、リモートアドレスをログに記録します。

sockaddr_in remote{};
socklen_t len = sizeof(remote);
int client = accept(srv, (sockaddr*)&remote, &len);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &remote.sin_addr, ip, sizeof(ip));
std::cout << "client " << ip << ":" << ntohs(remote.sin_port);

netcatでのテスト

ncを使ってエコーサーバーを対話的にテストします。

nc 127.0.0.1 8080
hello
hello       # echoed back

エコーの先へ

エコーサーバーは、次のように拡張できます。

  • 行ベースのプロトコル(HTTPに似たもの)
  • フレーム化されたバイナリプロトコル(長さプレフィックス)
  • JSONまたはProtobufメッセージ

確認問題

SO_REUSEADDRソケットオプションにはどのような目的がありますか。

まとめ

最小限のTCPエコーサーバーは、socket、setsockopt SO_REUSEADDR、bind、listen、acceptのループで構成されます。複数クライアントにはスレッドを生成するか、スレッドプールを使用します。大規模環境では非同期I/Oに切り替えます(次のレッスンで扱います)。

よくある質問

「TCPエコーサーバーの構築」レッスンは無料ですか?

はい。「TCPエコーサーバーの構築」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。

「TCPエコーサーバーの構築」で何を学びますか?

完全なTCPエコーサーバーの実装を順に学びます。 ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C++ Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「TCPエコーサーバーの構築」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC++ Academyレッスンでコードを書いて実行できますか?

はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. C++のBSDソケットAPI
  2. TCPエコーサーバーの構築
  3. epollとkqueueによる非同期I/O
  4. Boost Asioで現代的な非同期I/Oを使う
← C++ Academyに戻る