サーバーは子プロセスを生成しクライアントへデータを転送することによりデータ転送を管理します。親プロセスは接続要求の待機を行うためループを継続します。例 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) を使用することが可能です。