You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UNIX环境编程作业问询:循环读取多数据库条目与端口类型问题

解决APUE作业:循环读取网络数据库+端口号类型修正

刚好之前啃APUE的时候做过类似的作业,给你拆解下怎么搞定教授提的两个核心问题:

一、循环读取所有数据库条目

APUE第16.3.3章里的这些数据库查询函数,默认从第一条开始读,每次调用返回下一条,直到返回NULL就表示读完了。另外记得用setxxxent(1)初始化连接(参数1表示保持连接,不用每次重新打开数据库文件),读完后用endxxxent()关闭资源。下面给你每个数据库的循环示例:

1. 主机数据库(hostent)

#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>

// 读取所有主机条目
void print_hosts() {
    struct hostent *host;
    // 重置到数据库开头并保持连接
    sethostent(1);
    while ((host = gethostent()) != NULL) {
        printf("=== Host Entry ===\n");
        printf("Official Name: %s\n", host->h_name);
        
        // 打印别名列表
        char **alias;
        for (alias = host->h_aliases; *alias != NULL; alias++) {
            printf("Alias: %s\n", *alias);
        }
        
        // 打印IP地址(IPv4为例)
        char **addr;
        for (addr = host->h_addr_list; *addr != NULL; addr++) {
            char ip_str[INET_ADDRSTRLEN];
            inet_ntop(host->h_addrtype, *addr, ip_str, sizeof(ip_str));
            printf("Address: %s\n", ip_str);
        }
    }
    // 关闭数据库连接
    endhostent();
}

2. 网络数据库(netent)

和主机库逻辑几乎一致,用getnetent()循环:

void print_networks() {
    struct netent *net;
    setnetent(1);
    while ((net = getnetent()) != NULL) {
        printf("=== Network Entry ===\n");
        printf("Name: %s\n", net->n_name);
        printf("Address Type: %d\n", net->n_addrtype);
        printf("Network Number: %u\n", ntohl(net->n_net)); // 转主机字节序
    }
    endnetent();
}

3. 协议数据库(protoent)

用getprotoent()循环读取所有协议:

void print_protocols() {
    struct protoent *proto;
    setprotoent(1);
    while ((proto = getprotoent()) != NULL) {
        printf("=== Protocol Entry ===\n");
        printf("Name: %s\n", proto->p_name);
        printf("Protocol Number: %d\n", proto->p_proto);
    }
    endprotoent();
}

4. 服务数据库(servent)

这里要重点处理端口号的问题,先看循环逻辑:

void print_services() {
    struct servent *serv;
    setservent(1);
    while ((serv = getservent()) != NULL) {
        printf("=== Service Entry ===\n");
        printf("Name: %s\n", serv->s_name);
        // 端口号处理:转主机字节序+short类型
        short port = ntohs(serv->s_port);
        printf("Port: %hd\n", port); // %hd对应short类型输出
        printf("Protocol: %s\n", serv->s_proto);
    }
    endservent();
}

二、服务端口号的short类型修正

教授说端口应为short类型,原因和处理方式是:

  • struct servent里的s_port是网络字节序的16位无符号整数,但我们需要转成主机字节序的short(端口号范围0-65535,刚好是16位的取值范围)。
  • 用ntohs()把网络字节序转为主机字节序,然后赋值给short类型变量,输出时用%hd格式化(对应short类型的格式符)。

上面的print_services()函数已经做了这个处理,这样就不会再因为端口类型扣分了。

最后注意事项

  • 编译时直接用gcc your_code.c -o your_program即可,这些函数属于标准库,不需要额外链接网络库。
  • 如果运行时输出条目少,可能是系统的数据库文件(比如/etc/hosts、/etc/services)本身内容不多,但循环读取的逻辑是正确的,教授会认可这个实现。

内容的提问来源于stack exchange,提问作者Dawson Binder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:31:08