0Pricing
C Academy · レッスン

シンプルなエコーサーバー

複数のクライアントに同時対応します。

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

作成するもの

エコーサーバーはTCP接続を受け付け、クライアントが送信したバイト列をそのまま送り返します。ネットワークプログラミングにおける「Hello World」のようなものです。

epollを使って構築するため、1つのスレッドで多数のクライアントを同時に処理できます。構成要素は、接続待ちソケット、epollループ、そしてクライアントごとの読み取り後の書き込み処理です。

接続待ちソケットの作成

まずsocket()でIPv4 TCPエンドポイントを作成します。指定する3つの値は、AF_INET、SOCK_STREAM、プロトコル0です。

これによりファイルディスクリプタが返されます。これをbindし、ノンブロッキングに設定して、最終的にepollへ登録します。すべてのシステムコールで-1を確認してください。

int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) { perror("socket"); exit(1); }

アドレスの再利用

bindする前に、setsockopt()でSO_REUSEADDRを設定します。これにより、TIME_WAIT状態が終わるのを待たずに、サーバーを再起動して同じポートに再bindできます。

これを設定しないと、すぐに再起動した際にEADDRINUSEで失敗することがよくあり、開発中に困惑する原因になります。

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

ポートへのbind

struct sockaddr_inにアドレスファミリー、ポート、アドレスを設定します。ポートにはhtons()を使い、すべてのインターフェースで待ち受けるにはINADDR_ANYを使用します。

次にbind()を呼び出して、ソケットをそのアドレスに関連付けます。htonsはホストバイト順をネットワークバイト順に変換します。これは必須です。

struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(8080);
bind(listen_fd, (struct sockaddr*)&addr, sizeof addr);

listenとノンブロッキング設定

listen()を呼び出してソケットをパッシブにし、保留中の接続に対するバックログを設定します。SOMAXCONNを指定すると、システムの最大値を要求します。

次にソケットをノンブロッキングに切り替え、accept()がイベントループを停止させないようにします。これでepollに登録する準備が整います。

listen(listen_fd, SOMAXCONN);
set_nonblocking(listen_fd);

接続待ちソケットの登録

epollインスタンスを作成し、接続待ちソケットをEPOLLINで追加します。ここで読み取り可能イベントが発生した場合、新しいクライアントの接続を受け付けられることを意味します。

data.fdにfdを格納し、ループ内で接続待ちソケットを識別できるようにします。

int epfd = epoll_create1(0);
struct epoll_event ev = { .events = EPOLLIN, .data.fd = listen_fd };
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ev);

クライアントの接続受付

接続待ちソケットが読み取り可能になったら、accept()がEAGAINを返すまでループします。新しいクライアントソケットごとにノンブロッキングを設定し、EPOLLINで登録します。

これ以降、クライアントがエコー可能なデータを送信するたびに、epollが通知してくれます。

int c = accept(listen_fd, NULL, NULL);
if (c != -1) {
    set_nonblocking(c);
    struct epoll_event cev = { .events = EPOLLIN, .data.fd = c };
    epoll_ctl(epfd, EPOLL_CTL_ADD, c, &cev);
}

エコー処理のロジック

準備完了したクライアントから、recv()でバッファに読み込みます。バイト列を受け取ったら、同じバイト列をsend()ですぐに送り返します。

この単純な読み取り後の書き込みがエコー処理です。実運用では未送信データをバッファリングしますが、ここでは小さな応答が送信バッファに収まるものとします。

char buf[4096];
ssize_t r = recv(fd, buf, sizeof buf, 0);
if (r > 0) {
    send(fd, buf, r, 0);
}

切断の検出

recv()の戻り値が0の場合、クライアントが正常に接続を終了したことを意味します。EAGAIN以外の負の戻り値は実際のエラーです。

どちらの場合も、ディスクリプタをepollから削除し、close()してリソースを解放するとともに、それ以上イベントが発生しないようにします。

if (r == 0 || (r < 0 && errno != EAGAIN)) {
    epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
    close(fd);
}

完全なループ

各要素を組み合わせます。イベントを待ち、ディスクリプタが接続待ちソケットかクライアントかで分岐し、それぞれに応じて処理します。

このコンパクトなループだけで、完全に動作する並行エコーサーバーになります。1つのスレッドで多数のクライアントを処理し、接続ごとのスレッドは必要ありません。

for (;;) {
    int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
    for (int i = 0; i < n; i++) {
        if (events[i].data.fd == listen_fd) accept_clients();
        else echo_or_close(events[i].data.fd);
    }
}

テストと次のステップ

Linuxでコンパイルし、nc localhost 8080で接続してください。入力した内容がそのまま返ってきます。複数のターミナルを開いて、並行処理を確認しましょう。

堅牢性を高めるには、部分的な送信をバッファリングし、EPOLLOUTを処理し、EPOLLETに切り替えて最後まで読み出し、ハーフクローズにはEPOLLRDHUPを処理します。

確認テスト

エコーサーバーの処理の流れを理解できているか確認しましょう。

復習

epollを使ったエコーサーバーを構築しました。ソケットを作成し、SO_REUSEADDRを設定して、bind、listenを行い、ノンブロッキングにします。リスナーを登録し、ループ内でクライアントを受け付け、recv()/send()でエコーを返します。

0が返された場合は切断として扱い、適切にクローズします。この基本構成をもとに、高性能なシングルスレッドのネットワークサーバーへ発展させられます。

よくある質問

「シンプルなエコーサーバー」レッスンは無料ですか?

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

「シンプルなエコーサーバー」で何を学びますか?

複数のクライアントに同時対応します。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「シンプルなエコーサーバー」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. ブロッキングI/OとノンブロッキングI/O
  2. epollをセットアップする
  3. イベントループ
  4. シンプルなエコーサーバー
← C Academyに戻る