`
luliangok
  • 浏览: 816508 次
文章分类
社区版块
存档分类
最新评论

Beej’s Guide Network to Programming 系列连载08

 
阅读更多

5.调用/捕获系统函数

这部分我们使用系统的函数来访问网络他们在Unix的头文件里,以及任何支持套接字APP的操作系统(BSD、Windows、Linux、Mac等等)。当你调用他们中间的函数时,内核会自动帮助完成所有工作。

大多数就卡在这些系统函数里。在这儿,因为你可能发现没有可用的man!好,为了帮助顺利适应它,我按照你的程序调用系统函数的顺序来讲解他们。

那么,你需要一些牛奶和饼干,再给你提供一些样例代码。其它的就是你的勇气、高昂的勇气!你会发现原来竟然是如此的快乐!

(请注意,为了代码的简洁,没有包含错误检查。在调用getaddrinfo()函数成功时会返回一个有效的链表(linked list)。有些程序使用原始的地址(properly addressed ---也可译原型的地址)这也可以。)

5.1. getaddrinfo()---准备运行

这个是真正的默默无闻的函数,虽然它有没多参数,但是实际用起来很简单。它对于你建立一个地址结构起到了简化的作用。

一个小小的历史:它曾经是,你会使用所谓的gethostbyname ()的函数做DNS查找。然后你手工加载一些信息给结构SOCKADDR_IN ,并供你调用。

值得庆幸的是,这不再是必要的了。(如果你要编写工作在IPv4和IPv6的代码,使用上边所说的,也是不可取的!)在这现代化的时代,你已经有了getaddrinfo()函数并为你封装好了不少东西,其中包括DNS和服务名称查找,除了你自己填写所需要的结构!

让我们一起来看看!

#include<sys/types.h>

#include<sys/socket.h>

#include<netdb.h>

intgetaddrinfo(const char *node, //e.g. www.example.comor IP

const char *service, //e.g. “http” or port number

const struct addrinfo *hints,

struct addrinfo **res);

在这个函数里有3个输入参数和1个作为返回值的指向链表的指针res。

入参node是要连接的主机名或者IP地址。

下一个入参service是端口号,比如“80”,或者其它特定的服务名称像“http”

、“ftp”、“telnet”、“smtp”等等。

最后,入参hints指向一个你已经填写好了的addrinfo结构。

下面的示例是服务器在你的主机IP地址和端口号3490监听。请注意,他们没有做任何实际的监听或者网络设置;它只是在设置了结构hints并且做了调用。

int status;

struct addrinfohints;

struct addrinfo*servinfo; // will point to theresults

memset(&hints,0, sizeof(hints)); // make sure thestruct is empty

hints.ai_family =AF_UNSPEC; // don’t care IPv4 orIPv6

hints.ai_socktype= SOCK_STREAM; // TCP stream sockets

hints.ai_flags =AI_PASSIVE; // fill in myIP for me

if ((status =getaddreinfo(NULL, “3049”,&hints, &servinfo)) != 0) {

fprintf(stderr, “getaddrinfo error: %s\n”,gai_strerror(status));

exit(1);

}

// servinfo nowpoints to a linked list of 1 or more struct addrinfos

// … do everythinguntil you don’t need servinfo anymore …

// … do everythinguntil you don’t need servinfo anymore …

freeaddrinfo(servinfo);// free the linked-list

请注意:因为ai_family设置为AF_UNSPEC所以达到了与版本无关。你也能设置专为IPv4或者IPv6工作以及其它的地址族。

此外你在这儿看到了AI_PASSIVE标志;他告诉getaddrinfo()复制本机地址给套接字结构。这很好,因为没有硬编码。

译者注上边的情况通常使用在服务器端!

下边说的就是客户端的情况。

示例:连接到www.example.net的3049端口。

int status;

struct addrinfohints;

struct addrinfo *servinfo; // will point to the results

memset(&hints,0 sizeof(hints)); // make sure the structis empty

hints.ai_family =AF_UNSPEC; // don’t care IPv4 or IPv6

hints.ai_socktype= SOCK_STREAM; // TCP stream sockets

// get ready toconnect

status =getaddrinfo(www.example.net, “3049”, &hints, &servinfo);

// servinfo nowpoints to a linked list of 1 or more struct addrinfos

// etc.

我一直说servinfo是一个可以指向各种地址的指针。我们写一个简单的演示程序来显示不同的地址信息。这个程序在命令行上打印出你指定主机的IP地址。

showip.c

所需头文件列表:

#include<stdio.h>

#include<string.h>

#include<sys/types.h>

#include<sys/socket.h>

#include<netdb.h>

#include<arpa/inet.h>

流程图

正如您所看到的,代码调用的getaddrinfo()来填写由res指向的链表,然后我们可以遍历列表以及打印在命令行上。

译者注:测试IPv6失败!请读者自行查找国内可用的IPv6站点。

现在我们已经在控制之下,我们将使用getaddrinfo()得到的结果,我们要传递给其他socket函数,终于,建立我们的网络连接!请继续阅读!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics