1、第7章 IPv4和IPv6编程 知识点:IPv4和IPv6服务器的工作原理 IPv6如何为IPv4客户端服务 IPv6地址测试宏与IPv6套接口选项 IPv4客户与IPv6服务器 拥有双重协议栈的主机的一个基本持性是:其上运行的IPv6服务器既能应付IPv4客户,又能应付IPv6客户。这是通过使用IPv4映射的IPv6地址实现的。IPv4 TCP客户与一个IPv6服务器之间讲行通信的步骤。(1)启动IPv6服务器,创建一个IPv6的监听套接口,我们假定该套接口绑定了通配地址。(2)IPv4客户调用gethostbyname找到一个与该服务器对应的A记录。因为这台服务器主机同时支持IPv4和IP
2、v6,所以它应该既有一个A记录,又有一个AAAA记录,但IPv4的客户只需要一个A记录。(3)客户进程调用connect,客户主机向服务器发送一个IPv4的SYN。(4)服务器主机收到这个发往IPv6监听套接口的IPv4 SYN,置一个标志,表明这个连接使用IPv4映射的IPv6地址,然后响应一个IPv4的SYN/ACK。当这个连接建立后,accept返回给服务器的地址就是这个IPv4映射的IPv6地址。(5)在客户和服务器之间的所有通信使用IPv4数据报。(6)除非服务器明确地去检查这个IPv6地址是不是一个IPv4映射的IPv6地址(使用IN6_IS_ADDR_V4MAPPKD宏),它将不
3、会知道通信的对方是一个IPv4客户。双重协议栈屏蔽了这个细节。同样,IPv4的客户也不知道与之通信的是一个IPv6的服务器。对于一个IPv6的UDP服务器来说,情形是类似的,只需将每个数据报改变一次地址格式。例如一个IPv6服务器收到从IPv4客户发来的数据报,于是由recvfrom返回的地址将是该客户对IPv4映射的IPv6地址。同时服务器用这个映射的地址调用sendto对客户的请求作出响应。若是IPv6客户,则地址为IPv6地址,而不是映射后的地址。在此UDP服务器问题得到解决。下面来看当一个双重协议栈主机接收到数据时的处理,根据接收套接口的类型(TCP或UDP)对一个收到的IPv4或IP
4、v6 数据报进行如图7-2所示的处理。IPv6客户与IPv4服务器(1)如果IPv4的TCP客户调用connect时或IPv4的UDP客户调用sendto时指定的是一个IPv4地址,不需要作任何特殊处理。(2)如果IPv6的TCP客户调用connect时或IPv6的UDP客户调用sendto时指定的是一个IPv6地址,不需要作任何特殊处理。(3)如果IPv6的TCP客户调用connect时或IPv6的UDP客户调用sendto时指定的是一个IPv4映射的IPv6地址,内核会检测到这个映射地址,并发送一个IPv4数据报,而不是IPv6数据报。(4)IPv4客户不能在调用connect或sendt
5、o时指定一个IPv6地址,因为在IPv4的sockaddr_in结构里的4字节的in_addr结构中放不下一个16字节的IPv6地址。通过以上处理,也可以使IPv6客户与IPv4服务器通信,这就达到了从IPv4过渡到IPv6的目的。IPv6_ADDRFORM套接口选项 为什么要学习IPv6_ADDRFORM套接口选项呢?这得从它的功能说起,IPv6_ADDRFORM套接口选项能把一个套接口从一种类型转变成另一种类型。那为什么要转变地址格式呢?目的是在UNIX上文件描述字可以在进程之间进行传递,而最通常传递的方式就是通过fork来实现。假设进程创建了一个IPv4的监听套接口,然后接收到一个来自I
6、Pv4客户的连接。该服务器调用fork和exec,启动一个新程序处理客户请求。这个过程同以前介绍的并发服务器的唯一不同是将已连接套接口复制到事先约定的描述字,然后调用exec。但被加载的新程序期望一个这是IPv6套接口,而不是IPv4套接口,因此可以用IPv6_ADDBFORM套接口选项来转换该套接口的地址格式,如下:1.int af;2.socklen_t clilen;3.struct sockaddr_in6 cli;/*IPv6 struct*/4.struct hostent*ptr;5.af=AF_INET6;6.Setsockopt(STDIN_FILENO,IPPROTO_IP
7、V6,IPV6_ADDRFORM,&af,sizeof(af);7.clilen=sizeof(cli);8.Getpeername(0,&cli,&clilen);如果用IPv6_ADDRFORM作参数来调用getsockopt,返回值依赖于套接口地址的格式,将为AF_INET或AF_INET6。getsockopt和setsockopt的第二个参数可以是IPPROTO_IP或IPPROTO_IPV6。IPv6地址测试宏为测试IPv6地址的某些持性我们定义了总共12个宏来达到这个目的,如下:#include int IN6_IS_ADDR_UNSPECIFIED(const struct i
8、n6_addr *aptr);int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *aptr);int IN6_IS_ADDR_MULTICAST(const struct in6_addr *aptr);int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *aptr);int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *aptr);int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *aptr);int IN6_IS_A
9、DDR_V4COMPAT(const struct in6_addr *aptr);int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *aptr);int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *aptr);int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *aptr);int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *aptr);int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *aptr);返回值:若非零表示IPv6地址是指定类型的,否则返回0。源代码的可移植性 将gethostbuname()和gethostbyaddr()调用删除,转而使用getaddrinfo()和getnameinfo()函数。docin/sanshengshiyuandoc88/sanshenglu 更多精品资源请访问更多精品资源请访问