1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 支持苹果IPV6 ONLY 的socket 修改方法

支持苹果IPV6 ONLY 的socket 修改方法

时间:2023-04-07 22:47:31

相关推荐

支持苹果IPV6 ONLY 的socket 修改方法

首先别错误理解以为app 必须支持 ipv6 的服务端, 只需要支持 ipv6的客户端需要访问 ipv4 的服务端。

目前需要经过NAT64 转换就能达到目的,客户端只需要支持该转换就能实现, 在OS X的系统上是的wifi 共享有支持 NAT64转换,提供了这个功能就方便了我们可以使用手机链接 OS X上的热点模拟这个测试环境。

我们代码上所需要完成​的事情:

1.客户端需要链接的ip地址(ipv4) 通过转换。

1 getaddrinfo​ //方法可以转换为 ipv6 的地址。 2 3 ​struct addrinfo hints, *res, *res0; 4 5 memset(&hints, 0, sizeof(hints)); 6 7 hints.ai_family = PF_UNSPEC; 8 9 hints.ai_socktype = SOCK_STREAM;10 11 #if (PLATFORM == PLATFORM_WIN32)12 13 hints.ai_flags = AI_PASSIVE;14 15 #else16 17 hints.ai_flags = AI_DEFAULT;18 #endif

19 int error = getaddrinfo(pServerIP, "http", &hints, &res0);

2.经过转换后我们可以判断 ai_family 兼容 非NAT64 转换的网络环境与 NAT64转换的网络环境 下进行 socket的链接:

1 struct sockaddr_in addr_in; 2 3 struct sockaddr_in6 addr_in6; 4 5 int connect_ret; 6 7 for (res = res0; res; res = res->ai_next) { 8 9connect_ret = -1;10 11 tempSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);12 13if (tempSocket < 0) {14 15 continue;16 17 }18 19 if(AF_INET == res->ai_family){20 21 addr_in = *((struct sockaddr_in *)res->ai_addr);22 23 addr_in.sin_port = htons(ServerPort);24 25 connect_ret = connect(tempSocket, (struct sockaddr *)&addr_in, res->ai_addrlen);26 27 }else if(AF_INET6 == res->ai_family){28 29 addr_in6 = *((struct sockaddr_in6 *)res->ai_addr);30 31 addr_in6.sin6_port = htons(ServerPort);32 33 connect_ret = connect(tempSocket, (struct sockaddr *)&addr_in6, res->ai_addrlen);34 35 }36 37 if (connect_ret < 0) {38 39 cause = "connect";40 41 #if (PLATFORM == PLATFORM_WIN32)42 43 closesocket(tempSocket);44 45 #else46 47 close(tempSocket);48 49 #endif50 51 tempSocket = -1;52 53 continue;54 55 }56 57 break; 58 59 }

OK,这样就支持 ipv6 对 ipv4 的网络 而且兼容 普通 ipv4 对 ipv4 的网络。​

上面是没有考虑链接时候客户端会进入卡死状态直到链接成功, 因为加上去代码会复杂点,为了好看就没有加上, 真实项目中需要改为非阻塞模式, 通过select 来判断是否connect成功。

下面是加上非阻塞模式:

1int tempSocket = -1; 2struct addrinfo hints, *res, *res0; 3int error; 4const char *cause = NULL; 5 6memset(&hints, 0, sizeof(hints)); 7hints.ai_family = PF_UNSPEC; 8hints.ai_socktype = SOCK_STREAM; 9 10error = getaddrinfo(pServerIP, NULL, &hints, &res0);11if (error) {12 CCLOG("getaddrinfo error:%d", error);13 return false;14}15 16 17struct sockaddr_in addr_in;18struct sockaddr_in6 addr_in6;19for (res = res0; res; res = res->ai_next) {20 tempSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);21 if (tempSocket < 0) {22 cause = "socket";23 continue;24 }25 26 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)27 // 设定 非阻塞28 unsigned long tmepOption = 1; //0:阻塞29 ioctlsocket(tempSocket, FIONBIO, &tmepOption);30 #else31 // 设定 非阻塞32 int flag = fcntl(tempSocket, F_GETFL, 0);33 fcntl(tempSocket, F_SETFL, flag | O_NONBLOCK);34 #endif35 36 if(AF_INET == res->ai_family){37 addr_in = *((struct sockaddr_in *)res->ai_addr);38 addr_in.sin_port = htons(ServerPort);39 connect(tempSocket, (struct sockaddr *)&addr_in, res->ai_addrlen);40 }else if(AF_INET6 == res->ai_family){41 addr_in6 = *((struct sockaddr_in6 *)res->ai_addr);42 addr_in6.sin6_port = htons(ServerPort);43 connect(tempSocket, (struct sockaddr *)&addr_in6, res->ai_addrlen);44 }45 46 fd_set fset; 47 FD_ZERO(&fset); 48 FD_SET(tempSocket, &fset);49 50 timeval timeout;51 timeout.tv_sec = 1; // 1.5秒超时, 上层逻辑会尝试3次 >> 1.5 * 352 timeout.tv_usec = 500; 53 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)54 socklen_t len = sizeof(error);55 #else56 int len = sizeof(error);57 #endif58 if( select(tempSocket+1, NULL, &fset, NULL, &timeout) > 0) 59 { 60 if (FD_ISSET(tempSocket, &fset))61 {62 getsockopt(tempSocket, SOL_SOCKET, SO_ERROR, (char *)&error, &len); 63 if(error == 0){64 break;65 }66 }67 }68 69 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)70 closesocket(tempSocket);71 #else72 close(tempSocket);73 #endif74 tempSocket = -1; 75 76}77 78if (tempSocket < 0) {79 CCLOG("connect server error:%d", tempSocket);80 goto RETURN_FALSE;81}82 83 84if(false){85 RETURN_FALSE:86 freeaddrinfo(res0);87 return false;88}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。