AppStore审核的时候反馈:
We discovered one or more bugs in your app when reviewed on iPad and iPhone running iOS 10.2 on Wi-Fi connected to an IPv6 network.
因此我需要修改IPv6环境下的支持。使用了socket的时候仅支持了IPv4
1.在网络连通性检测的时候使用了socket:
原来的表现:在IPv6环境下显示网络连接不通,包括直接IP访问(192.168.1.22)和域名访问(baidu.com)
修改后结果:IP访问和域名访问都显示可以成功访问(都可以直接获取的IPv6格式的地址)
原理不再赘述,详见最下面的链接
主要修改的是:
1) gethostbyname —> getaddrinfo
2)根据getaddrinfo做IPv4和IPv6的区分
3)添加sockaddr_in6等IPv6相关内容
修改后代码:
/**
@brief 测试连接
*/
+ (void)testConnection:(NSString*)host port:(NSNumber*)port compelete:(nullable void(^)(BOOL isSuccess))compelete {
if(!host){
compelete(NO);
}
NSOperationQueue *operationQueue = [[NSOperationQueue alloc]init];
[operationQueue addOperationWithBlock:^{
// NSString * host =@"123.33.33.1";
// NSNumber * port = @1233;
// 创建 socket
int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == socketFileDescriptor) {
NSLogD(@"创建失败");
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
compelete(NO);
}];
return;
}
NSLogD(@"host %@:%@",host,port);
// 获取 IP 地址
int error, sockfd;
const char *cause = NULL;
struct addrinfo hints, *res, *res0;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_DEFAULT;
error = getaddrinfo([host UTF8String], "http", &hints, &res0);
NSLogD(@"getaddrinfo %d",error);
if (0 != error) {
close(socketFileDescriptor);
NSLogD(@"%@",@"无法解析服务器的主机名");
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
compelete(NO);
}];
return;
}
sockfd = -1;
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
char ipbuf[28];
for (res = res0; res; res = res->ai_next) {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0) {
cause = "socket";
continue;
}
if(AF_INET6==res->ai_family){
addr6 = (struct sockaddr_in6 *)res->ai_addr;
addr6->sin6_port = htons([port intValue]); // 修改端口号
printf("%s\n", inet_ntop(AF_INET6, &addr6->sin6_addr, ipbuf, 28));
// 连接 socket
if (connect(sockfd, (struct sockaddr *) addr6, sizeof(*addr6)) < 0) {
cause = "connect v6";
close(sockfd);
sockfd = -1;
continue;
}
}else{
addr = (struct sockaddr_in *)res->ai_addr;
addr->sin_port = htons([port intValue]);
printf("%s\n", inet_ntop(AF_INET, &addr->sin_addr, ipbuf, 16));
// // 设置为非阻塞
// fcntl(sockfd,F_SETFL,fcntl(sockfd,F_GETFL,0)|O_NONBLOCK);
// 连接 socket
if (connect(sockfd, (struct sockaddr *) addr, sizeof(*addr)) < 0) {
// if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
cause = "connect";
close(sockfd);
sockfd = -1;
continue;
}
}
break; /* okay we got one */
}
if (sockfd < 0) {
/*NOTREACHED*/
NSLog(@"error cause %s", cause);
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
compelete(NO);
}];
return;
}
NSLogD(@"连接成功%@",host);
close(sockfd);
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
compelete(YES);
}];
}];
}
调用访问网络的方法:
[Utils testConnection:service port:@(port) compelete:^(BOOL isSuccess) {
if(isSuccess){
// success
}else{
// failure
}
}];
2.在访问服务端接口的时候用了socket
与上述方法相同,只不过根据需求设置成阻塞/非阻塞的,看最后是否需要调用close(sockfd);关闭此连接
PS.
1.IPv6环境的搭建
1)用wifi:http://www.jianshu.com/p/632d995749e1
2)用4G:http://www.cnblogs.com/SUPER-F/p/IPV6.html
2.官方指导和使用