在ios应用的开发中,如果项目中网络层用的是SOCKET 底层 的api。需要在工程做 兼容ipv4和ipv6网络环境的处理。
解决方案:
服务器地址配置为域名,通过解析域名的方式,得到 该域名映射的ip地址,再通过这个ip地址,去进行网络通信。
就是将服务器的地址,通过域名解析函数,解析为相应网络环境的ip地址。再通过这个ip地址,去和服务器通信。
如果客户端是在ipv6网络环境下,解析服务器地址的时候,会得到一个ipv6的地址。在客户端根据这个服务器的ipv6地址,建立客户端ipv6 网络环境下的 socket 通信;
如果客户端是在ipv4网络环境下,解析服务器地址的时候,会得到一个ipv4的地址。在客户端根据这个服务器的ipv4地址,建立客户端ipv4 网络环境下的 socket 通信;
因为ipv4和ipv6网络环境下,有很多api不同,因此,不同网络,要做不同判断。
实践证明,如果服务器不是配置的域名,而是配置的Ipv4的一个地址,不会 影响 我们程序的正常解析。
我们可以通过解析出来的 addrinfo结构体中 协议族(AF_INET、AF_INET6),知道当前客户端网络环境是Ipv4还是ipv6
核心代码:
1.解析服务器的域名(或服务器的 ipv4地址);
2.得到和客户端这边网络环境匹配的ip地址(如果客户端网络环境是ipv4,解析得到的是一个ipv4的地址;如果客户端网络环境是ipv6,解析得到的是一个ipv6的地址)
3.调用相应 网络环境下的 socket连接方法,实现socket的连接。
int NS_Socket::Connect(const char *Host, unsigned short Port)
{
struct addrinfo * result;
struct addrinfo * res;
int error;
error = getaddrinfo(Host, NULL, NULL, &result);
if(error != 0) {
NSLog(@"error in getaddrinfo:%d", error);
return NS_SOCKET_ERROR_HOST_NOTFOUND;
}
for(res = result; res!=NULL; res = res->ai_next) {
char hostname[1025] = "";
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, 1025, NULL, 0, 0);
NSLog(@"hostname=%s",hostname);
if(error != 0) {
NSLog(@"error in getnameifno: %s", gai_strerror(error));
continue;
}
else {
switch (res->ai_addr->sa_family)
{
case AF_INET6:
{
if(subConnectServerIPV6(hostname ,Port)==0)
{
NSLog(@"6连接成功");
freeaddrinfo(result);
return 0;
}else{
return subConnectServerIPV6(hostname ,Port);
}
}
break;
case AF_INET:
{
if(subConnectServerIPV4(hostname ,Port)==0)
{
NSLog(@"4连接成功");
freeaddrinfo(result);
return 0;
}else
{
return subConnectServerIPV4(hostname ,Port);
}
}
break;
default:
break;
}
NSLog(@"hostname: %s ", hostname);
}
}
return NS_SOCKET_ERROR_CONNECT;
}
本地搭建IPv6测试环境
首先需要的就是一台用非Wi-Fi的方式上网的Mac电脑。其本质就是用Mac做一个热点,然后用iPhone连接这个Wi-Fi,区别是这次我们产生的是一个本地的IPv6 DNS64/NAT64网络,这项功能是OS X 10.11新加的。和我们以前开启热点方式不一样的地方在于,我们在“System Preferences”界面选中“Sharing”的同时,要按住“Option”键。
之后在“Sharing”界面中,我们会看到和之前不一样的地方,就是红框所标的地方,多了一个叫“Create NAT64 Network”的选框,选中它。之后就是按照正常的创建热点的流程走完就行了。