プログラミングインタフェース

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

一部のサービスでは、データグラムソケットを使用します。rwho(1) サービスは、LAN に接続されたホストについての状態情報を提供します。ネットワークトラフィックが重くなるため、in.rwhod(1M) は実行しないでください。rwho サービスは、特定のネットワークに接続されたすべてのホストに情報をブロードキャストします。rwho サービスは、データグラムソケットを使用する例の 1 つです。

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


例 8–8 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) サーバープロセスによって状態情報が周期的にブロードキャスト送信されます。このサーバープロセスも状態情報を受信します。このサーバープロセスはまた、データベースを更新します。このデータベースは、各ホストの状態のために解釈されます。サーバーはそれぞれ個別に動作し、ローカルネットワークとそのブロードキャスト機能によってのみ結合されます。

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

次に、rwho(1) サーバープロセスの簡単な例を示します。このコードは、まず、ネットワーク上のほかのホストからブロードキャストされた状態情報を受信し、次に、このコードを実行しているホストの状態情報を提供します。最初のタスクは、プログラムのメインループで行われます。rwho(1) ポートで受信したパケットを調べて、そのパケットが別の rwho(1) サーバープロセスから送信されたことを確認し、到着時刻を記録します。次に、パケットはホストの状態でファイルを更新します。一定の時間内にホストからの通信がない場合、データベースルーチンはホストが停止していると想定し、この情報を記録します。ホストが稼働している間にはサーバーが停止していることもあるので、このアプリケーションはよくエラーになります。


例 8–9 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) サーバープロセスに知らせる必要があります。このタスクはタイマーで実行されます。このタスクはシグナルによって起動されます。

状態情報は、ローカルネットワーク上でブロードキャスト送信されます。ブロードキャストをサポートしないネットワークでは、マルチキャストを使用してください。