在过去的几天里,我收到了Apple对我的应用程序的拒绝 . 我的应用程序与UDP通信,远程服务器始终是IPv4 . 我使用过BSD套接字 . 请指导我如何解决这个问题 .
我曾尝试使用IPv4网络创建NAT64热点,但我无法将任何数据包发送到服务器 . 此外,我现在没有IPv6可用 .
来自Apple:
2.2详细信息我们在运行iOS 9.3.2的iPad和在Wi-Fi和蜂窝网络上运行iOS 9.3.2的iPhone上查看了应用程序中的一个或多个错误 . 具体来说,在审核期间,我们无法绕过“初始化”页面 . 我们在等待加载应用时遇到错误 . 我们附上了截图供您参考 . 后续步骤请在设备上运行您的应用以识别问题,然后修改并重新提交您的应用以供审核 . 应用程序在IPv6网络上进行审核 . 请确保您的应用支持IPv6网络,因为需要IPv6兼容性 . 有关支持IPv6网络的其他信息,请参阅支持iPv6 DNS64 / NAT64网络 .
源代码贝娄:
UdpSocketManager.h >>
#ifndef UDP_SOCKET_MANAGER_H__
#define UDP_SOCKET_MANAGER_H__
#import "TInetAddr.h"
class UdpSocketManager
{
public:
UdpSocketManager();
~UdpSocketManager();
void getLocalAddress();
void initializeSocket();
void start();
void stop();
void sendSignal(int p_type, TInetAddr *p_destAddress, unsigned char *p_data, int p_length);
void receiveSignal();
int localPort;
int signalingSocket;
int signalSocketRecvLength;
int socketFamily;
int isIPV4Available;
int isIPV6Available;
char wifiIP[INET_ADDRSTRLEN];
char cellularIP[INET_ADDRSTRLEN];
char wifiIP_v6[INET6_ADDRSTRLEN];
char cellularIP_v6[INET6_ADDRSTRLEN];
long returnLength;
struct sockaddr_in remoteAddrForRecv;
struct sockaddr_in srcAddrV4;
struct sockaddr_in6 srcAddrV6;
struct sockaddr_in sendAddr4;
struct sockaddr_in6 sendAddr6;
bool running;
pthread_t thread;
};
#endif
UdpSocketManager.m >>
#include <string.h>
#include <pthread.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "UdpSocketManager.h"
#import <Foundation/Foundation.h>
unsigned int ipAddressToUnsignedInt(char *ipAddress)
{
unsigned int ipAddressLongValue = 0L;
int byteSegment = 0;
for(int i = 0; i < strlen(ipAddress); i++)
{
char ch = ipAddress[i];
if(ch == '.')
{
ipAddressLongValue <<= 8;
ipAddressLongValue |= byteSegment;
byteSegment = 0;
}
else
{
byteSegment = byteSegment * 10 + (ch - 48);
}
}
ipAddressLongValue <<= 8;
ipAddressLongValue |= byteSegment;
return ipAddressLongValue;
}
int custom_random(int max=65535)
{
int randomValue;
randomValue = arc4random_uniform(65535)%max;
return randomValue;
}
int custom_random(int min, int max)
{
int randomValue;
randomValue = arc4random_uniform(max);
if(randomValue<min)
randomValue=(min+custom_random(max-min));
return randomValue;
}
void* runUdpSocketManager(void *objRef)
{
UdpSocketManager *THIS = (UdpSocketManager *) objRef;
THIS->running=true;
while (THIS->running)
{
THIS->receiveSignal();
}
pthread_exit(NULL);
return 0;
}
UdpSocketManager::UdpSocketManager()
{
socketFamily=AF_INET;
signalingSocket=-1;
running=false;
initializeSocket();
}
UdpSocketManager::~UdpSocketManager()
{
}
void UdpSocketManager::getLocalAddress()
{
//Read local address
getLocalAddress();
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success=0;
isIPV4Available=FALSE;
isIPV6Available=FALSE;
success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL)
{
if(temp_addr->ifa_addr->sa_family==AF_INET)
{
if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:@"en"])
{
isIPV4Available=TRUE;
strcpy(wifiIP, inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
printf("IP Address: %s\n",inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
}
else if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:@"pdp_ip0"])
{
isIPV4Available=TRUE;
strcpy(cellularIP, inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
printf("IP Address: %s\n",inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
}
}
else if(temp_addr->ifa_addr->sa_family==AF_INET6)
{
if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:@"en"])
{
isIPV6Available=TRUE;
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr), (char*)wifiIP_v6, INET6_ADDRSTRLEN);
printf("Interface: %s IPV6: %s\n",temp_addr->ifa_name,wifiIP_v6);
}
else if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:@"pdp_ip0"])
{
isIPV6Available=TRUE;
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr), (char*)cellularIP_v6, INET6_ADDRSTRLEN);
printf("Interface: %s IPV6: %s\n",temp_addr->ifa_name,cellularIP_v6);
}
}
temp_addr = temp_addr->ifa_next;
}
}
freeifaddrs(interfaces);
}
void UdpSocketManager::initializeSocket()
{
if(signalingSocket!=-1)
close(signalingSocket);
if (isIPV4Available)
{
if((signalingSocket=socket(AF_INET, SOCK_DGRAM, 0))==-1)
{
NSLog(@"Unable to create signaling socket of AF_INET");
}
else
{
socketFamily=AF_INET;
NSLog(@"Socket created successfully. [AF_INET]");
}
}
else if(!isIPV4Available && isIPV6Available)
{
if((signalingSocket=socket(AF_INET6, SOCK_DGRAM, 0))==-1)
{
NSLog(@"Unable to create signaling socket of AF_INET6");
}
else
{
socketFamily=AF_INET6;
NSLog(@"Socket created successfully. [AF_INET6]");
}
}
else
{
if((signalingSocket=socket(AF_INET, SOCK_DGRAM, 0))==-1)
{
NSLog(@"Unable to create signaling socket of AF_INET");
}
else
{
socketFamily=AF_INET;
NSLog(@"Socket created successfully. [AF_INET]");
}
}
int count=0;
while(true)
{
count++;
if(socketFamily==AF_INET)
{
srcAddrV4.sin_len = sizeof(srcAddrV4);
srcAddrV4.sin_family = socketFamily;
srcAddrV4.sin_addr.s_addr = INADDR_ANY;
srcAddrV4.sin_port = htons(localPort);
if (bind(signalingSocket, (struct sockaddr *) &srcAddrV4, sizeof(srcAddrV4)) < 0)
{
NSLog(@"[AF_INET] ERROR occured creating signaling port at attempt (%d) Port: %d", count, localPort);
localPort=(int)custom_random(1024, 65535);
}
else
{
int on=1;
setsockopt(signalingSocket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
setsockopt(signalingSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
NSLog(@"[AF_INET] SignalingSocket Created Successfully at attempt (%d) Port: %d\n", count, localPort);
break;
}
}
else
{
srcAddrV6.sin6_len = sizeof(srcAddrV6);
srcAddrV6.sin6_family = socketFamily;
srcAddrV6.sin6_addr = in6addr_any;
srcAddrV6.sin6_port = htons(localPort);
if (bind(signalingSocket, (struct sockaddr *) &srcAddrV6, sizeof(srcAddrV6)) < 0)
{
NSLog(@"[AF_INET] ERROR occured creating signaling port at attempt (%d) Port: %d", count, localPort);
localPort=(int)custom_random(1024, 65535);
}
else
{
int on=1;
setsockopt(signalingSocket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
setsockopt(signalingSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
NSLog(@"[AF_INET6] SignalingSocket Created Successfully at attempt (%d) Port: %d\n", count, localPort);
break;
}
}
}
}
void UdpSocketManager::start()
{
pthread_create(&thread, NULL, runUdpSocketManager, (void *) this);
}
void UdpSocketManager::stop()
{
running=false;
}
void UdpSocketManager::receiveSignal()
{
int port;
char ipAddress[16];
socklen_t fromlen;
unsigned char udpSignalRecvBuffer[1600];
fromlen = sizeof(remoteAddrForRecv);
signalSocketRecvLength = (int)recvfrom(signalingSocket, (char *)udpSignalRecvBuffer,1600,0,(struct sockaddr *)&remoteAddrForRecv,&fromlen);
if(signalSocketRecvLength>0)
{
strcpy(ipAddress, inet_ntoa(remoteAddrForRecv.sin_addr));
port = ntohs(remoteAddrForRecv.sin_port);
NSLog(@"RECEIVED %d bytes from %s:%d", signalSocketRecvLength, ipAddress, port);
}
else
{
usleep(10000);// 10 ms
}
}
void UdpSocketManager::sendSignal(int p_type, TInetAddr *p_destAddress, unsigned char *p_data, int p_length)
{
if(socketFamily==AF_INET6)
{
// Convert IPv4 address to IPv4-mapped-into-IPv6 address.
sendAddr6.sin6_family = AF_INET6;
sendAddr6.sin6_port = p_destAddress->m_port;
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[0] = 0;
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[1] = 0;
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[2] = htonl(0xffff);
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[3] = ntohl(ipAddressToUnsignedInt(p_destAddress->m_address));
sendAddr6.sin6_addr.__u6_addr.__u6_addr16[4] = 0;
sendAddr6.sin6_addr.__u6_addr.__u6_addr16[5] = 0xffff;
char ipV6Address[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &sendAddr6.sin6_addr, ipV6Address, INET6_ADDRSTRLEN);
NSLog(@"ipV6Address: %s\n", ipV6Address);
sendAddr6.sin6_flowinfo = 0;
sendAddr6.sin6_scope_id = 0;
}
else
{
sendAddr4.sin_family = AF_INET;
sendAddr4.sin_port = htons(p_destAddress->m_port);
if(inet_aton((char *) p_destAddress->m_address, &sendAddr4.sin_addr)==0)
{
NSLog(@"signal message - inet_aton() failed, %s", p_destAddress->m_address);
}
}
if(socketFamily==AF_INET)
returnLength=sendto(signalingSocket, p_data, p_length, 0, (struct sockaddr *)&sendAddr4, sizeof(sendAddr4));
else
returnLength=sendto(signalingSocket, p_data, p_length, 0, (struct sockaddr *)&sendAddr6, sizeof(sendAddr6));
NSLog(@"SENT %ld bytes to %s:%d\n", returnLength,p_destAddress->m_address,p_destAddress->m_port);
}
3 回答
我不认为你的"Convert IPv4 address to IPv4-mapped-into-IPv6 address"是正确的 . 您应该使用您想要连接的东西的字符串(可以是主机名或IPv4地址文字)来调用
getaddrinfo()
,而不是尝试自己构建地址,它将返回给您一个sockaddr
的列表;你应该使用那里的第一个传递给sendto
. 它将为您提供适当的IP地址系列,如果您提供IPv4地址并且它是仅IPv6网络(无需进行任何测试),它将自动为您提供用于该NAT64的正确IPv6地址路由器(你无需自己解决这个问题) . (如果您想使用NAT64 / DNS64从IPv4手动构建IPv6地址而不使用getaddrinfo()
,则必须遵循RFC 7050中的复杂过程 . )此外,您在
getLocalAddress()
中所做的所有事情都是不必要的,并可能导致更多问题 . 你不需要isIPV4Available
或isIPV6Available
- 你不应该在意这一点 . 只需在开始时创建并绑定IPv4和IPv6套接字(无需关心哪个工作),每次需要发送时,如上所述使用getaddrinfo()
得到正确的sockaddr
,然后发送到套接字其地址族对应于您正在使用的sockaddr
. 当你想要接收时,你在两个套接字上调用recvfrom
.我看到您显示的代码有几个问题:
UdpSocketManager
在调用initializeSocket()
之前未调用getLocalAddress()
,因此绑定套接字始终为IPv4,而不是IPv6 . 在调用initializeSocket()
之前,您也没有初始化localPort
.getLocalAddress()
(如果有人调用过)调用自身,所以你有一个无限的递归循环 .在循环中使用
custom_random()
来挑选随机绑定端口是完全错误的,不必要的,并且可能无休止 . 要在配置的端口出现故障时选择随机端口,只需调用bind()
一次,并将端口设置为0.操作系统知道哪些端口可用,并为您选择可用的随机端口 . 你的整个initializeSocket()
过于复杂,无法尝试做什么 . 它可以大大简化 .启用
SO_REUSEADDR
时,必须在调用bind()
之前启用它,而不是之后启用 . 另见SO_REUSEPORT
.您的
remoteAddrForRecv
变量被声明为sockaddr_in
,它仅足以容纳IPv4地址,并且如果在IPv6套接字上调用,将导致recvfrom()
失败 . 请改用sockaddr_storage
. 事实上 . 所有sockaddr_in
和sockaddr_in6
变量都应替换为sockaddr_storage
.inet_ntoa()
同样也是仅限IPv4的 . 请改用inet_ntop()
来处理IPv4和IPv6地址 .尝试更像这样的东西:
UdpSocketManager.h
UdpSocketManager.m
Solution for AFNetworking for reachability in IPv6 and IPv4
在类 AFNetworkReachabilityManager 中更改以下代码