5.1. getaddrinfo()-准备开始!
这是个有很多选项(options)的工作马(workhorse)函数,但是却相当容易上手。它帮你设定之後需要的 struct。
谈点历史:它前身是你用来做 DNS 查询的 gethostbyname()。而当时你需要手动将资料写入 struct sockaddr_in,并在你的调用中使用。
感谢老天,现在已经不用了。[如果你想要设计能通用於 IPv4 与 IPv6 的程序也不用!]在现代,你有 getaddrinfo() 函数,可以帮你做许多事情,包含 DNS 与 service name 查询,并填好你所需的 structs。
让我们来看看!
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *node, // 例如: "www.example.com" 或 IP
const char *service, // 例如: "http" 或 port number
const struct addrinfo *hints,
struct addrinfo **res);你给这个函数三个输入参数,结果它会返回一个指向链表的指针给你 - res。
node 参数是要连接的主机名,或者一个 IP address(地址)。
下一个参数是 service,这可以是 port number,像是 "80",或者特定的服务名[可以在你 UNIX 系统上的 IANA Port List [17] 或 /etc/services 文件中找到],像是 "http" 或 "ftp" 或 "telnet" 或 "smtp" 诸如此类的。
[17] http://www.iana.org/assignments/port-numbers
最後,hints 参数指向一个你已经填好相关资料的 struct addrinfo。
这里是一个调用示例,如果你是一部 server(服务器),想要在你主机上的 IP address 及 port 3490 运行 listen。
要注意的是,这边实际上没有做任何的 listening 或网路设置;它只有设置我们之後要用的 structures 而已。
注意一下,我将 ai_family 设置为 AF_UNSPEC,这样代表我不用管我们用的是 IPv4 或 IPv6 address。如果你想要指定的话,你可以将它设置为 AF_INET 或 AF_INET6。
还有,你会在这里看到 AI_PASSIVE flag;这个会告诉 getaddrinfo() 要将我本地端的地址(address of local host)指定给 socket structure。这样很好,因为你就不用写固定的地址了[或者你可以将特定的地址放在 getaddrinfo() 的第一个参数中,我现在写 NULL 的那个参数]。
然後我们进行调用,若有错误发生时[getaddrinfo 会返回非零的值],如你所见,我们可以使用 gai_strerror() 函数将错误打印出来。若每件事情都正常运作,那麽 serinfo 就会指向一个 struct addrinfos 的链表,表中的每个成员都会包含一个我们之後会用到的某种 struct sockaddr。
最後,当我们终於使用 getaddrinfo() 配置的链表完成工作後,我们可以[也应该]要调用 freeaddrinfo() 将链表全部释放。
这边有一个调用示例,如果你是一个想要连接到特定 server 的 client,比如是:"www.example.net"的 port 3490。再次强调,这里并没有真的进行连接,它只是设置我们之後要用的 structure。
如你所见,代码使用你在命令行输入的参数调用 getaddrinfo(),它填好 res 所指的链表,并接着我们就能重复那行并打印出东西或做点类似的事。
[有点不好意思!我们在讨论 struct sockaddrs 它的型别差异是因 IP 版本而异之处有点鄙俗。我不确定是否有较优雅的方法。]
在下面运行示例!来看看大家喜欢看的运行画面:
现在已经在我们的掌控之下,我们会将 getaddrinfo() 返回的结果送给其它的 socket 函数,而且终於可以建立我们的网路连接了!
让我们继续看下去!
[17] http://www.iana.org/assignments/port-numbers
Last updated