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

非同期ネットワーク通信

この項ではリアルタイムアプリケーション用の XTI/TLI を使用した非同期ネットワーク通信の方法を説明しています。SunOS は非同期ネットワークの XTI/TLI イベントの処理を、STREAMS 非同期機能と XTI/TLI ライブラリルーチンの非ブロッキングモードの組み合わせによりサポートしています。

ネットワークプログラミングモデル

ファイルおよびデバイス I/O と同様にネットワーク転送は、プロセスサービス要求による同期または非同期の実行が可能です。

同期ネットワーキング

同期ネットワーキングはファイルおよびデバイス I/O 同様に進行します。write(2) 関数と同様、送信要求はメッセージのバッファー化が行われてから戻されますが、バッファー領域がすぐに確保できない場合は、呼び出し処理を中断する可能性もあります。read(2) 関数と同様、受信要求は必要なデータが到着するまで呼び出し処理の実行を中断させます。 SunOS ではトランスポートサービスの範囲に関する保証は存在しないため、他のデバイスに関連する形でのリアルタイム処理を目的とした使用においての同期ネットワーキングの使用は不適切であるといえます。

非同期ネットワーキング

非同期ネットワーキングは非ブロッキングサービス要求により提供されます。また、データが送信または受信される接続の確立時にアプリケーションが非同期通知を要求することも可能です。

非同期コネクションレスモードサービス

非同期コネクションレスモードネットワーキングはエンドポイントに非ブロッキングサービスを構成し、データの転送時期をポーリングまたは非同期通知によって受信することにより行われます。非同期通知が使用された場合、実際のデータの受信は通常シグナルハンドラ内で行われます。

エンドポイントの非同期化

エンドポイントの確立が t_open(3NSL) により行われ、t_bind(3NSL) により識別が確立された後、エンドポイントを非同期サービスで使用するために構成することが可能です。これは fcntl(2) 関数を使用し、エンドポイント上に O_NONBLOCK フラグを設定することにより可能です。これにより、使用可能なバッファー領域がすぐに確保できない場合、t_sndudata(3NSL) への呼び出しは -1 を戻し、t_errnoTFLOW に設定します。同様に、データが存在しない場合、 t_rcvudata(3NSL) への呼び出しは -1 を戻し、t_errnoTNODATA に設定します。

非同期ネットワーク転送

データの着信、またはエンドポイント上でのデータ受信待機のチェックを定期的に行うためにアプリケーションが poll(2) 関数を使用することは可能ですが、データが着信した場合に非同期通知の受信が必要な場合があります。ioctl(2) 関数の I_SETSIG を使用することにより、エンドポイント上にデータが着信した場合、プロセスに SIGPOLL シグナルの送信要求を行うことが可能です。アプリケーション側では複数のメッセージが単一のシグナルとして送信されないようチェックを行うべきです。

以下の例でアプリケーションによって選択されたトランスポートプロトコルの名前は protocol です。


#include <sys/types.h>
#include <tiuser.h>
#include <signal.h>
#include <stropts.h>

int				fd;
struct t_bind				*bind;
void				sigpoll(int);

	fd = t_open(protocol, O_RDWR, (struct t_info *) NULL);

	bind = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
	...     /*バインドされるアドレスの設定*/
	t_bind(fd, bind, bin

	/*エンドポイントを非ブロッキング化*/
	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

	/*SIGPOLL 用のシグナルハンドラを確立*/
	signal(SIGPOLL, sigpoll);

	/*受信データが存在する場合 SIGPOLL を要求*/
	ioctl(fd, I_SETSIG, S_INPUT | S_HIPRI);

	...

void sigpoll(int sig)
{
	int					flags;
	struct t_unitdata					ud;

	for (;;) {
		... /*ud を初期化 */
		if (t_rcvudata(fd, &ud, &flags) < 0) {
			if (t_errno == TNODATA)
				break;  /* メッセージが存在しない */
			... /*他のエラー状態の処理 */
	}
	... /*ud 内のメッセージの処理*/
}

非同期コネクションモードサービス

コネクションモードサービスでは、データ転送のみではなく、接続の確立そのものを非同期で行うようアプリケーションによって設定することが可能です。操作のシーケンスは他のプロセスに接続しようとしている場合と、接続を待機している場合とで異なります。

非同期による接続の確立

プロセスは接続を試み、非同期で接続を完了することが可能です。プロセスは最初に接続エンドポイントを作成し、fcntl(2) を使用してエンドポイントを非ブロッキング操作を行うように構成します。コネクションレスデータ転送同様、エンドポイントは接続の確立時とそれ以降のデータ転送に対し非同期通知が行われるよう構成することも可能です。それに続き接続プロセスは t_connect(3NSL) 関数を使用して転送設定の初期化を行います。その後、t_rcvconnect(3NSL) 関数を使用して接続の確立の確認が行われます。

接続の非同期使用

非同期状態で接続の待機を行う場合、プロセスは最初にサービスアドレスにバインドされた非ブロッキングエンドポイントを確立します。poll(2) の結果、または非同期通知によって接続要求の着信が伝えられた場合、プロセスは t_listen(3NSL) 関数を使用して接続要求を取得します。プロセスは接続を受け付けるために t_accept(3NSL) 関数を使用します。応答を行うエンドポイントは非同期データ転送を行うため個別に構成されている必要があります。

以下の例では非同期による接続要求を行う方法を示しています。


#include <tiuser.h>
int             fd;
struct t_call   *call;

	fd = .../*非ブロッキングエンドポイントを確立*/

	call = (struct t_call *) t_alloc(fd, T_CALL, T_ADDR);
	.../*call 構造体の初期化*/
	t_connect(fd, call, call);

	/*接続要求は非同期で進行*/

	.../*接続が受け付けられた通知を受信*/
	t_rcvconnect(fd, &call);

以下の例では非同期接続の待機の方法を示しています。


#include <tiuser.h>
int             fd, res_fd;
struct t_call   call;

	fd = ... /*非ブロッキングエンドポイントを確立*/

	.../*接続要求が着信した通知を受信*/

	call = (struct t_call *) t_alloc(fd, T_CALL, T_ALL);
	t_listen(fd, &call);

	.../*接続を受け付けるか拒否するかの判定*/
	res_fd = ... /*応答用に非ブロッキングエンドポイントを確立*/

	t_accept(fd, res_fd, call);

非同期オープン

アプリケーションが、リモートホストからマウントされたファイスシステム、または初期化が長期化する可能性のあるデバイス上の通常ファイルを動的に開く必要性が発生する場合があります。このようなファイルオープン作業を行っている場合、アプリケーションは他のイベントに対するリアルタイム応答が行えません。SunOS ではこの問題を解決するために、第 2 のプロセスに実際のファイルオープン作業を行わせ、ファイル記述子をリアルタイム処理に渡す機能が提供されています。

ファイル記述子の転送

SunOS の STREAMS インタフェースでは 1 つのプロセスから別のプロセスへオープンファイル記述子を渡すメカニズムを装備しています。オープンファイル記述子を持つプロセス ioctl(2) 関数の引数 I_SENDFD を使用します。もう 1 つのプロセスは ioctl(2) の引数 I_RECVFD を使用してファイル記述子を取得します。

この例では、親プロセスはテストファイルに関する情報を出力し、パイプを作成します。次に親は、テストファイルを開き、パイプを使用してオープンファイル記述子を親へ戻す子プロセスを作成します。その後、親プロセスは新しいファイル記述子の状態情報を表示します。


例 3-13 ファイル記述子転送

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stropts.h>
#include <stdio.h>

#define TESTFILE "/dev/null"
main(int argc, char *argv[])
{
	int fd;
	int pipefd[2];
	struct stat statbuf;

	stat(TESTFILE, &statbuf);
	statout(TESTFILE, &statbuf);
	pipe(pipefd);
	if (fork() == 0) {
		close(pipefd[0]);
		sendfd(pipefd[1]);
	} else {
		close(pipefd[1])
		recvfd(pipefd[0]);
	}
}

sendfd(int p)
{
	int tfd;

	tfd = open(TESTFILE, O_RDWR);
	ioctl(p, I_SENDFD, tfd);
}

recvfd(int p)
{
	struct strrecvfd rfdbuf;
	struct stat statbuf;
	char			fdbuf[32];

	ioctl(p, I_RECVFD, &rfdbuf);
	fstat(rfdbuf.fd, &statbuf);
	sprintf(fdbuf, "recvfd=%d", rfdbuf.fd);
	statout(fdbuf, &statbuf);
}

statout(char *f, struct stat *s)
{
	printf("stat: from=%s mode=0%o, ino=%ld, dev=%lx, rdev=%lx¥n",
		f, s->st_mode, s->st_ino, s->st_dev, s->st_rdev);
	fflush(stdout);
}