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
相关产品推荐
相关产品推荐

