IPv4的TCP客户和一个IPv6的TCP服务器进行通信的步骤如下:
1.IPv6服务器启动后创建一个IPv6的监听套接字,我们假定服务器把通配地址捆绑到该套接字
2.IPv4客户调用gethostbyname找到服务器主机的一个A记录。服务器主机既有一个A记录,又有一个AAAA记录,因为它同时支持IPv4和IPv6,不过IPv4客户需要的只是一个A记录
3.客户调用connect,导致客户主机发送一个IPv4 SYN到服务器主机
4.服务器主机接收这个目的地为IPv6监听套接字的IPv4 SYN,设置一个标志指示本连接应使用IPv4映射的IPv6地址,然后响应以一个IPv4 SYN/ACK。该连接建立后,由accept返回给服务器的地址就是这个IPv4映射的IPv6地址
5.当服务器主机往这个IPv4映射的IPv6地址发送TCP分节时,其IP栈产生目的地址为所映射IPv4地址的IPv4载送数据报。因此,客户和服务器之间的所有通信都使用IPv4的载送数据报。
6.除非服务器显示检查这个IPv6地址是不是一个IPv4映射的IPv6地址(IN6_IS_ADDR_V4MAPPED),否则它永远不知道自己是在与一个IPv4客户通信。这个细节由双协议栈处理。同样地,IPv4客户也不知道自己是在与一个IPv6服务器通信
上述情形的一个支撑性假设是:双栈服务器主机既有一个IPv4地址,又有一个IPv6地址。在所有的IPv4地址耗尽之前,这个假设没有问题。
IPv6的UDP服务器也有类似的情形,不过每个数据报的地址格式可能有所变动。举例来说,如果IPv6服务器收到来自某个IPv4客户的一个数据报,由recvfrom返回的地址将是该客户的IPv4映射的IPv6地址。服务器以这个IPv4映射的IPv6地址调用sendto给出对本客户请求的响应。这个地址格式告知内核向客户发送一个IPv4数据报。然而服务器收到的下一个数据报可能是一个IPv6数据报,recvfrom将返回客户的IPv6地址。如果服务器给出响应,那么内核将产生一个IPv6数据报。
如果收到一个目的地为某个IPv4套接字的IPv4数据报,那么无需任何特殊处理。客户和服务器之间交换的是IPv4数据报。
如果收到一个目的地为某个IPv6套接字的IPv6数据报,那么无需任何特殊处理。客户和服务器之间交换的是IPv6数据报。
如果收到一个目的地为某个IPv6套接字的IPv4数据报,那么内核把与该数据报的源IPv4地址对应的IPv4映射的IPv6地址作为accept(TCP)或recvfrom(UDP)返回的对端IPv6地址。客户和服务器之间交换的是IPv4数据报。
相反则是行不通,因为一般来说,一个IPv6地址无法表示成一个IPv4地址。
如果一个IPv6的TCP客户指定一个IPv4映射的IPv6地址以调用connect,或者一个IPv6的UDP客户指定一个IPv4映射的IPv6地址以调用sendto,那么内核检测到这个映射地址后改为发送一个IPv4数据报而不是IPv6数据报。
不论调用connect还是调用sendto,IPv4客户都不能指定一个IPv6地址,因为16个字节的IPv6地址超出了IPv4的sockaddr_in结构中的in_addr成员结构的4字节长度。
大多数双栈主机在处理监听套接字时应使用以下规则:
1.IPv4监听套接字只能接受来自IPv4客户的外来连接。
2.如果服务器有一个绑定了通配地址的IPv6监听套接字,而且该套接字未设置IPV6_V6ONLY套接字选项,那么该套接字既能接受来自IPv4客户的外来连接,又能接受来自IPv6客户的外来连接。对于来自IPv4客户的连接而言,其服务器端的本地地址将是与某个本地IPv4地址对应的IPv4映射的IPv6地址。
3.如果服务器有一个IPv6监听套接字,而且绑定在其上的是除IPv4映射的IPv6地址以外的某个非通配IPv6地址,或者绑定在其上的是通配地址,不过还设置了IPV6_V6ONLY套接字选项,那么该套接字只能接受来自IPv6客户的外来连接。
有一小类的IPv6应用进程必须清楚与其通信的是不是IPv4对端。这些应用程序需要知道对端的地址是不是一个IPv4映射的IPv6地址。
双栈主机上的IPv6服务器既能服务于IPv4客户,又能服务于IPv6客户。IPv4客户发送给这种服务器的仍然是IPv4数据报,不过服务器的协议栈会把客户主机的地址转换成一个IPv4映射的IPv6地址,因为IPv6服务器仅仅处理IPv6套接字地址结构。
类似地,双栈主机上的IPv6客户能够和IPv4服务器通信。客户的解析器会把服务器主机所有的A记录作为IPv4映射的IPv6地址返回给客户,而客户指定这些地址之一调用connect将会使双栈发送一个IPv4 SYN分节。
只有少量的客户和服务器需要知道对端使用的具体协议(例如FTP),而对端是否在使用IPv4可使用IN6_IS_ADDR_V4MAPPED宏来做判定。