プログラミングインタフェース

帯域外データ

ストリームソケットの抽象化には、帯域外データが含まれます。帯域外データは、接続されたストリームソケットペア間の論理的に独立した伝送チャネルです。帯域外データは通常データとは無関係に配信されます。帯域外データ機能が使用される場合、一度に 1 つ以上の帯域外メッセージが確実に配信されなければなりません。このメッセージには 1 バイト以上のデータを含むことができます。また、いつでも 1 つ以上のメッセージの配信を保留できます。

帯域内シグナリングでは、緊急データは通常データと一緒に順番どおりに配信され、メッセージは通常データストリームから抽出されます。抽出されたメッセージは個別に格納されます。したがって、ユーザーは中間のデータをバッファリングせずに、緊急データを順番どおりに受信するか、順不同で受信するかを選択できます。

MSG_PEEK を使用すると、帯域外データを先読みできます。ソケットにプロセスグループがある場合は、その存在がプロトコルに通知される時に SIGURG シグナルが生成されます。プロセスは適切な fcntl(2) 呼び出しを使用して、プロセスグループ ID またはプロセス ID が SIGURG を配信するように設定できます (SIGIO に関する 「割り込み方式のソケット入出力」を参照)。複数のソケットに配信待ちの帯域外データがある場合は、例外状況用に select(3C) を呼び出し、どのソケットがこのようなデータを保留しているかを判断してください。

帯域外データが送信された位置のデータストリームには、論理マークが置かれます。リモートログインアプリケーションとリモートシェルアプリケーションは、この機能を使用してクライアントプロセスとサーバープロセス間にシグナルを伝達します。シグナルが受信された時点で、データストリームの論理マークまでのデータはすべて破棄されます。

帯域外メッセージを送信するには、MSG_OOB フラグを send(3SOCKET) または sendto(3SOCKET) に指定します。帯域外データを受信するには、MSG_OOB フラグを recvfrom(3SOCKET) または recv(3SOCKET) に指定します。帯域外データを順番どおりに取得する場合、MSG_OOB フラグは必要ありません。SIOCATMARK ioctl(2) は、読み取りポインタが現在、データストリーム内のマークを指しているかどうかを示します。

int yes;
ioctl(s, SIOCATMARK, &yes);

yes1 で返される場合、次の読み取りはマークのあとのデータを返します。yes が 1 でない場合は、帯域外データが到着したと想定して、次の読み取りは帯域外シグナルを送信する前にクライアントによって送信されたデータを提供します。割り込みシグナルまたは終了シグナルを受信したときに出力をフラッシュするリモートログインプロセス内のルーチンを以下に示します。このコードは通常データを破棄を示すマークまで読み取った後、帯域外バイトを読み取ります。

プロセスは、初めにマークまでを読み取らずに、帯域外データの読み取りまたは先読みを行うこともできます。基底のプロトコルが通常データと一緒に帯域内にある緊急データを配信するときに、その存在だけを前もって通知する場合、このようなデータにアクセスすることはより困難になります。このようなタイプのプロトコルの例としては、TCP (インターネットファミリにソケットストリームを提供するときに使用されるプロトコル) があります。このようなプロトコルでは、MSG_OOB フラグを使用して recv(3SOCKET) を呼び出したときに、帯域外バイトが到着していないことがあります。このような場合、呼び出しはエラー EWOULDBLOCK を返します。また、入力バッファー内の帯域内データの量によっては、ピアはバッファーが空になるまで (通常のフロー制御によって) 緊急データを送信できなくなる場合があります。この場合、プロセスが待ち行列に入ったデータを十分に読み取って入力バッファーをクリアしてからでないと、ピアは緊急データを送信できません。


例 8–10 帯域外データの受信時における端末入出力のフラッシュ

#include <sys/ioctl.h>
#include <sys/file.h>
...
oob()
{
    int out = FWRITE;
    char waste[BUFSIZ];
    int mark = 0;
 
    /* flush local terminal output */
    ioctl(1, TIOCFLUSH, (char *) &out);
    while(1) {
        if (ioctl(rem, SIOCATMARK, &mark) == -1) {
            perror("ioctl");
            break;
        }
        if (mark)
            break;
        (void) read(rem, waste, sizeof waste);
    }
    if (recv(rem, &mark, 1, MSG_OOB) == -1) {
        perror("recv");
        ...
    }
    ...
}

ソケットストリームのインライン (帯域内) にある緊急データの位置を保持する機能もあります。この機能は、ソケットレベルのオプションである SO_OOBINLINE として提供されます。使用法については、getsockopt(3SOCKET) のマニュアルページを参照してください。このソケットレベルのオプションを使用すると、緊急データの位置を保持できます。ただし、MSG_OOB フラグを指定しない場合、通常データストリームにおいてマークの直後にある緊急データが返されます。複数の緊急指示を受信するとマークは移動しますが、帯域外データが消失することはありません。