编程接口指南

套接字和服务器

大多数服务器都是通过已知 Internet 端口号或 UNIX 系列名称进行访问的。服务 rlogin 便是已知的 UNIX 系列名称。示例 7–7 中给出了远程登录服务器的主循环。

服务器将从其调用方的控制终端分离出来,除非服务器在 DEBUG 模式下运行。

   (void) close(0);

   (void) close(1);

   (void) close(2);

   (void) open("/", O_RDONLY);

   (void) dup2(0, 1);

   (void) dup2(0, 2);

   setsid();

进行分离可防止服务器从控制终端的进程组接收信号。服务器从控制终端分离之后,便不能将错误报告发送到终端。已分离的服务器必须使用 syslog(3C) 记录错误。

服务器通过调用 getaddrinfo(3SOCKET) 获取其服务定义。

    bzero(&hints, sizeof (hints));

    hints.ai_flags = AI_ALL|AI_ADDRCONFIG;

    hints.ai_socktype = SOCK_STREAM;

    error = getaddrinfo(NULL, "rlogin", &hints, &api);

api 中返回的结果包含程序侦听服务请求所用的 Internet 端口。/usr/include/netinet/in.h 中定义了某些标准端口号。

然后,服务器创建套接字并侦听服务请求。bind(3SOCKET) 例程可以确保服务器在预期位置进行侦听。由于远程登录服务器会侦听受限的端口号,因此该服务器将以超级用户身份运行。 服务器的主体是以下循环。


示例 7–7 服务器主循环

    /* Wait for a connection request. */

    for (;;) {

        faddrlen = sizeof (faddr);

        new_sock = accept(sock, (struct sockaddr *)api->ai_addr,

                   api->ai_addrlen)

        if (new_sock == -1) {

            if (errno != EINTR && errno != ECONNABORTED) {

                perror("rlogind: accept");

            }

            continue;

        }

        if (fork() == 0) {

            close (sock);

            doit (new_sock, &faddr);

        }

        close (new_sock);

    }

    /*NOTREACHED*/

accept(3SOCKET) 将阻止消息,直到客户机请求服务为止。此外,如果 accept 被某信号(如 SIGCHLD)中断,则 accept(3SOCKET) 会返回故障指示。如果发生错误,则会检查来自 accept(3SOCKET) 的返回值,并使用 syslog(3C) 记录错误。

然后,服务器派生一个子进程,并调用远程登录协议处理的主体。父进程用于对连接请求进行排队的套接字将在子进程中关闭。accept(3SOCKET) 所创建的套接字将在父进程中关闭。将客户机的地址传递到服务器应用程序的 doit() 例程,此例程用来验证客户机。