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

コネクションレス型のサーバー

サービスの中にはデータグラムソケットを使用するものがあります。rwho(1) サービスは、LAN に接続されたホストのステータス情報を提供します (in.rwhod(1M) は大量のネットワークトラフィックを発生させるため、実行を避けてください)。rwho(1) サービスを利用するには、特定のネットワークに接続されたすべてのホストに情報をブロードキャスト送信できる環境が必要です。これは、データグラムソケットを使用する例の 1 つです。

rwho(1) サーバーを実行するホスト上のユーザーは、ruptime(1) を使用して別のホストの現在のステータスを取得できます。典型的な出力を例 2-10 に示します。


例 2-10 ruptime(1) プログラムの出力

itchy up 9:45, 5 users, load 1.15, 1.39, 1.31
scratchy up 2+12:04, 8 users, load 4.67, 5.13, 4.59
click up 10:10, 0 users, load 0.27, 0.15, 0.14
clack up 2+06:28, 9 users, load 1.04, 1.20, 1.65
ezekiel up 25+09:48, 0 users, load 1.49, 1.43, 1.41
dandy 5+00:05, 0 users, load 1.51, 1.54, 1.56
peninsula down 0:24
wood down 17:04
carpediem down 16:09
chances up 2+15:57, 3 users, load 1.52, 1.81, 1.86

各ホストには、rwho(1) サーバープロセスによってステータス情報が周期的にブロードキャスト送信されます。このサーバープロセスもステータス情報を受信し、データベースを更新します。このデータベースは、各ホストのステータスのために解釈されます。サーバーはそれぞれ個別に動作し、ローカルネットワークとそのブロードキャスト機能によってのみ結合されます。

大量のネットトラフィックが生成されるため、ブロードキャストの使用はかなり困難です。サービスが広範に、かつ頻繁に使用されない限り、周期的なブロードキャストのために手間がかかり簡潔さが失われることになります。

例 2-11 は、rwho(1) サーバーの簡潔な例を示しています。このコードは、ネットワーク上のほかのホストによるステータス情報ブロードキャストを受信し、そのホストのステータスを供給するという 2 つのタスクを行います。最初のタスクは、プログラムのメインループで行われます。別の rwho(1) サーバープロセスによって送信されたことを確認するために rwho(1) ポートで受信されたパケットがチェックされ、到着時刻が記録されます。パケットは、続いてホストのステータスを使用してファイルを更新します。一定の時間内にホストからの通信がない場合、データベースルーチンはホストがダウンしていると想定し、そのことを記録します。ホストが稼動している間サーバーがダウンしていることがあるため、このアプリケーションはエラーになりがちです。


例 2-11 rwho(1) サーバー

main()
{
   ...
   sp = getservbyname("who", "udp");
   net = getnetbyname("localnet");
   sin.sin6_addr = inet_makeaddr(net->n_net, in6addr_any);
   sin.sin6_port = sp->s_port;
   ...
   s = socket(AF_INET6, SOCK_DGRAM, 0);
   ...
   on = 1;
   if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof on)
         == -1) {
      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
      exit(1);
   }
   bind(s, (struct sockaddr *) &sin, sizeof sin);
   ...
   signal(SIGALRM, onalrm);
   onalrm();
   while(1) {
      struct whod wd;
	      int cc, whod, len = sizeof from;
      cc = recvfrom(s, (char *) &wd, sizeof(struct whod), 0,
         (struct sockaddr *) &from, &len);
      if (cc <= 0) {
      if (cc == -1 && errno != EINTR)
         syslog(LOG_ERR, "rwhod: recv: %m");
      continue;
      }
      if (from.sin6_port != sp->s_port) {
         syslog(LOG_ERR, "rwhod: %d: bad from port",
            ntohs(from.sin6_port));
         continue;
      }
      ...
      if (!verify( wd.wd_hostname)) {
         syslog(LOG_ERR, "rwhod: bad host name from %x",
            ntohl(from.sin6_addr.s6_addr));
         continue;
      }
      (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
      whod = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
      ...
      (void) time(&wd.wd_recvtime);
      (void) write(whod, (char *) &wd, cc);
      (void) close(whod);
   }
   exit(0);
}

2 つ目のサーバータスクは、そのホストのステータスの供給です。このタスクでは、周期的にシステムステータス情報を取得し、その情報をメッセージとしてパッケージ化し、ほかの rwho(1) サーバーに知らせるためローカルネットワーク上でそれをブロードキャスト送信する必要があります。このタスクはタイマーで実行され、シグナルによって起動されます。システムステータス情報の位置確認が伴いますが、重要なものではありません。

ステータス情報が、ローカルネットワーク上でブロードキャスト送信されます。ブロードキャストをサポートしないネットワークでは、別の方式を使用してください。