ネットワークインタフェース

帯域外データ

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

帯域内シグナリングだけをサポートする (つまり、緊急のデータが通常のデータと共に順序どおり配信される) 通信プロトコルでは、メッセージは通常のデータストリームから抽出され、個別に格納されます。これにより、ユーザーは間に入るデータをバッファリングする必要にせまられることなく、緊急データを順番に受信するか順不同で受信するかを選択できます。

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

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

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

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

戻り時に yes1 の場合、次の読み取りはマークのあとのデータを返します。yes が 1 でない場合は、帯域外データが到着したと仮定して、次の読み取りは帯域外シグナルを送信する前にクライアントによって送信されたデータを提供します。割り込みまたは停止のシグナルを受ける場合に出力をフラッシュするリモートログインプロセス内のルーチンを、例 2-12 に示します。このコードは、マークまでの通常のデータを (これを破棄するために) 読み取り、続いて帯域外バイトを読み取ります。

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


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

#include <sys/ioctl.h>
#include <sys/file.h>
...
oob()
{
		int out = FWRITE;
		char waste[BUFSIZ];
		int mark = 0;
 
		/* ローカル端末出力をフラッシュする */
		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 フラグなしで返される通常のデータストリーム内のマークの直後に続きます。複数の緊急指示を受信するとマークは移動しますが、帯域外データが消失することはありません。