0Pricing
C Academy · レッスン

複数クライアントの処理

select と poll です。

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

並行処理の問題

単純なサーバーは、一度に 1 つのクライアントだけを処理します。あるクライアントの処理が遅いと、ほかのクライアントはすべて待たされます。多数のクライアントを同時に処理するには、別のモデルが必要です。

並行処理のアプローチ

一般的な方法は 3 つあります。

  • クライアントごとにスレッドまたはプロセスを作成:単純ですが、大規模になると負荷が高くなります
  • select や poll によるI/O 多重化:1 つのスレッドで多数のソケットを監視します
  • epoll/kqueue によるイベントループ:数千の接続まで拡張できます

select の動作

select() はファイルディスクリプタの集合を監視し、1 回のブロッキング呼び出しで、読み取りや書き込みの準備ができているもの、またはエラーが発生しているものを通知します。これにより、1 つのスレッドで多数のソケットを処理できます。

fd_set の基本

select は fd_set ビットマスクを使用します。FD_ZERO、FD_SET、FD_CLR、FD_ISSET のマクロで操作します。

#include <sys/select.h>

void setup_set(fd_set *set, int listen_fd) {
    FD_ZERO(set);          /* clear all */
    FD_SET(listen_fd, set); /* watch the listener */
}

select の呼び出し

select には、最大の fd に 1 を加えた値が必要です。また、準備ができたディスクリプタを示すように集合をその場で変更します。この変更は破壊的なので、呼び出す前に毎回集合を作り直します。

#include <sys/select.h>
#include <stdio.h>

int wait_ready(int maxfd, fd_set *read_set) {
    int n = select(maxfd + 1, read_set, NULL, NULL, NULL);
    if (n < 0) perror("select");
    return n; /* number of ready fds */
}

select を使ったサーバーループ

基本的な流れは、集合を作り直し、select を呼び出し、準備ができた各 fd を処理することです。リスナーであれば新しいクライアントを accept し、クライアントであればデータを読み取ります。

#include <sys/select.h>

void loop_skeleton(int listen_fd, fd_set *master, int maxfd) {
    fd_set work;
    for (;;) {
        work = *master;           /* copy, select destroys it */
        select(maxfd + 1, &work, NULL, NULL, NULL);
        for (int fd = 0; fd <= maxfd; fd++) {
            if (!FD_ISSET(fd, &work)) continue;
            /* fd == listen_fd -> accept; else -> recv */
        }
    }
}

クライアントの管理

新しい接続を accept したら、その fd をマスター集合に追加し、maxfd を更新します。クライアントが切断したら(recv が 0 を返したら)、close を呼び、集合から FD_CLR で削除します。

#include <sys/select.h>
#include <unistd.h>

void add_client(fd_set *master, int *maxfd, int conn) {
    FD_SET(conn, master);
    if (conn > *maxfd) *maxfd = conn;
}
void drop_client(fd_set *master, int conn) {
    close(conn);
    FD_CLR(conn, master);
}

select の制限

select には次のような欠点があります。

  • FD_SETUP 個のディスクリプタまでに制限されます(多くの場合 1024 個)
  • 呼び出すたびにすべての fd を O(n) で走査します
  • 反復のたびに集合を作り直す必要があります

多数の接続を扱う場合は、poll や epoll のほうが拡張性に優れています。

poll の特徴

poll() は固定ビットマスクではなく struct pollfd の配列を受け取るため、1024 個のディスクリプタ制限がなく、呼び出しのたびに入力を破壊することもありません。

#include <poll.h>

void setup_poll(struct pollfd *pfd, int listen_fd) {
    pfd[0].fd = listen_fd;
    pfd[0].events = POLLIN; /* notify when readable */
}

poll の呼び出し

poll は、少なくとも 1 つの fd の準備ができるまで(またはタイムアウトするまで)ブロックし、その後、準備ができた各エントリの revents を設定します。

#include <poll.h>
#include <stdio.h>

int poll_ready(struct pollfd *pfds, int count) {
    int n = poll(pfds, count, -1); /* -1 = block forever */
    if (n < 0) perror("poll");
    return n;
}

大規模化:epoll

数千の接続を扱う場合、Linux の epoll(および BSD の kqueue)は、select や poll が行う全体走査を避け、イベントごとに準備ができたディスクリプタだけを O(1) で返します。

理解度チェック

複数のクライアントの処理についての理解度を確認しましょう。

まとめ

1 つのスレッドで多数のクライアントを処理する方法を学びました。

  • select で多数の fd を監視し、FD_ マクロで管理します
  • select は破壊的に集合を変更するため、ループごとに集合を作り直します
  • accept したクライアントを集合に追加し、切断時に削除します
  • poll には 1024 個の制限がなく、epoll は数千の接続に対応できます

よくある質問

「複数クライアントの処理」レッスンは無料ですか?

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

「複数クライアントの処理」で何を学びますか?

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

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

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

「複数クライアントの処理」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. ソケットの概要
  2. TCP サーバー
  3. TCP クライアント
  4. 複数クライアントの処理
← C Academyに戻る