编程接口指南

无连接服务器

某些服务使用数据报套接字。rwho(1) 服务提供了有关连接到局域网的主机的状态信息。应避免运行 in.rwhod(1M),因为 in.rwho 会导致网络通信流量过大。rwho 服务将信息广播到所有连接到特定网络的主机。rwho 服务是数据报套接字用法示例。

运行 rwho(1) 服务器的主机上的用户可以使用 ruptime(1) 获取其他主机的当前状态。以下示例给出了典型输出。


示例 7–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) 服务器进程发送并标记有到达时间。然后,这些包使用主机的状态更新文件。如果长时间没有收到来自主机的消息,则数据库例程认为此主机已关闭并记录此信息。由于主机正常运行时服务器可能会关闭,因此该应用程序容易出现错误。


示例 7–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);

}

第二项服务器任务是提供其主机状态。这要求定期获取系统状态信息,将其打包在消息中,并在本地网络上广播,以使其他 rwho(1) 服务器收到这些信息。此任务由计时器运行,并由信号触发。

状态信息将在本地网络上广播。对于不支持广播的网络,使用多点传送。