サーバーは子プロセスを生成しクライアントへデータを転送することによりデータ転送を管理します。親プロセスは接続要求の待機を行うためループを継続します。例 3-7 で示すとおり、サーバーでは子プロセスの生成を行うため run_server が呼び出されます。
connrelease()
{
/*ここで必要なため conn_fd はグローバル*/
if (t_look(conn_fd) == T_DISCONNECT) {
fprintf(stderr, "connection aborted¥n");
exit(12);
}
/*上記以外の場合、正常型解放を要求-通常終了*/
exit(0);
}
run_server(listen_fd)
int listen_fd;
{
int nbytes;
FILE *logfp; /*ログファイルへのファイルポインタ*/
char buf[1024];
switch(fork()) {
case -1:
perror("fork failed");
exit(20);
default: /*親*/
/* conn_fd を閉じ、戻って再び待機する*/
if (t_close(conn_fd) == -1) {
t_error("t_close failed for conn_fd");
exit(21);
}
return;
case 0: /*子*/
/* listen_fd を閉じ、サービスを行う */
if (t_close(listen_fd) == -1) {
t_error("t_close failed for listen_fd");
exit(22);
}
if ((logfp = fopen("logfile", "r")) == (FILE *) NULL) {
perror("cannot open logfile");
exit(23);
}
signal(SIGPOLL, connrelease);
if (ioctl(conn_fd, I_SETSIG, S_INPUT) == -1) {
perror("ioctl I_SETSIG failed");
exit(24);
}
if (t_look(conn_fd) != 0){ /*切断するかどうか*/
fprintf(stderr, "t_look: unexpected event¥n");
exit(25);
}
while ((nbytes = fread(buf, 1, 1024, logfp)) > 0)
if (t_snd(conn_fd, buf, nbytes, 0) == -1) {
t_error("t_snd failed");
exit(26);
}
フォーク後、親プロセスは待機のメインループへ戻ります。子プロセスは新たに確立されたトランスポート接続を管理します。フォークが失敗した場合、exit(2) が両方のトランスポートエンドポイントを閉じ、クライアントに接続の切断要求を送り、クライアントの t_connect(3NSL) 呼び出しは失敗します。
サーバーの処理はログファイルから一度に 1024 バイトを読み込み、クライアントに t_snd(3NSL) を使用して送ります。buf はデータバッファーの開始点を指し、nbytes は送信するデータのバイト数を指定します。4 つ目の引数には、0 または以下の 2 つのオプションフラグを指定することが可能です。
この例ではどちらのフラグもサーバーによって設定されていません。
ユーザーがトランスポートプロバイダをデータであふれさせた場合、トランスポートから十分なデータが取り除かれるまで t_snd(3NSL) がブロックを行います。
t_snd(3NSL) は接続の切断要求を捜しません (接続が切断したことを表示)。接続が中止された場合、データが失われる可能性があるためサーバーへ通知する必要があります。1 つの解決法は、各 t_snd(3NSL) 呼び出しの前、または t_snd(3NSL) 失敗の後に、着信するイベントのチェックを行うよう t_look(3NSL) を呼び出すことです。例ではより整理された手法を使用しています。ioctl(2) の I_SETSIG によって指定されているイベントが発生した場合にユーザー要求をシグナルにします。 streamio(7I) のマニュアルページを参照してください。S_INPUT によりエンドポイント conn_fd に入力が着信した場合にシグナルをユーザープロセスへ送信します。接続の切断要求が着信した場合、シグナルを検知するルーチン (connrelease) がエラーメッセージを出力し、終了します。
サーバーが t_snd(3NSL) および t_rcv(3NSL) 呼び出しを交互に行う場合、着信する接続の切断要求を認識するために、t_rcv(3NSL) を使用することが可能です。