使用CocoaAsyncSocket適配IPv6幾天前已經(jīng)審核通過了,剛旅行回來,以下補上關鍵代碼护蝶,有問題的朋友,直接留言吧翩迈。
前提:之所有提到使用CocoaAsyncSocke適配IPv6持灰,是因為我的應用本身是社交應用,使用socket和服務器連接负饲。
近些天堤魁,我負責的幾個app都遇到因為IPv6導致服務器連接不上喂链,從而蘋果的審核人員無法登錄應用而把應用拒絕的問題,事實上妥泉,我朋友在WWDC跟蘋果的工作人員溝通椭微,發(fā)現(xiàn)非常非常多的中國應用都遇到這個問題,沒有通過審核盲链。以上是我花了不少時間才搞定的解決方案蝇率,其實最后做出來真的超級簡單。
蘋果審核反饋的信息如下:
蘋果在IPv6的環(huán)境下審核刽沾,最終失敗本慕。經(jīng)過驗證,我們發(fā)現(xiàn)確實如此侧漓。
介紹一下间狂,我們的應用網(wǎng)絡模塊的情況。所有的數(shù)據(jù)都是從socket收發(fā)火架,應用初次啟動的時候鉴象,本地是沒有業(yè)務服務器的IP和端口的,所以應用先連到服務器獲取這些業(yè)務服務器的IP和端口何鸡,我們稱這個服務器為服務列表服務器纺弊。socket是直接使用的第三方組件CocoaAsyncSocket。
連接服務列表服務器也是通過socket連接骡男,在連接的時候淆游,先通過一個在代碼里面寫死的一個IPv4的地址進行連接,如果連接不通隔盛,則通過解析一個寫死的URL獲取到地址之后再次進行連接犹菱,連接上之后從服務器獲取真實的業(yè)務服務器的IP和端口,并連接這些業(yè)務服務器吮炕,注意這里返回的業(yè)務服務器IP也是IPv4格式的腊脱。
以上邏輯在IPv4的環(huán)境里面是正常的,但是在IPv6的環(huán)境里面就不行了龙亲,主要是IPv4格式的IP不能在IPv6里面使用陕凹,所以雖然第一次通過預置的IP連接服務列表服務器失敗,會解析URL獲取到IPv6格式的IP鳄炉,但是從服務列表服務器拿到的IP仍然是IPv4格式的杜耙,無法使用。
所以一切的問題都指向一個:IPv4格式的IP無法在IPv6的網(wǎng)絡環(huán)境里面使用拂盯。
解決方案:如果當前是處于IPv6的網(wǎng)絡環(huán)境中佑女,那就對該IPv4的IP進行轉換,拿到一個IPv6格式的IP進行連接。
代碼邏輯:CocoaAsyncSocket里面有一個類方法
+ (NSMutableArray*)lookupHost:(NSString*)hostport:(uint16_t)porterror:(NSError**)errPtr
通過這個傳入一個IPv4的IP或者傳入一個URL可以查到對應的IPv6的IP团驱,前提是在IPv6的網(wǎng)絡環(huán)境下簸呈,如果是在IPv4的網(wǎng)絡環(huán)境下,只會拿到IPv4的IP店茶,當判斷查到的array里面有IPv6的IP的時候就直接用這個進行連接蜕便,否則用IPv4的IP進行連接
關鍵代碼:
//針對ipv6網(wǎng)絡環(huán)境下適配,ipv4環(huán)境直接使用原來的地址
- (NSString*)getProperIPWithAddress:(NSString*)ipAddrport:(UInt32)port
{
NSError *addresseError = nil;
NSArray *addresseArray = [GCDAsyncSocket lookupHost:ipAddr
port:port
error:&addresseError];
if (addresseError) {
NSLog(@"");
}
NSString *ipv6Addr = @"";
for (NSData *addrData in addresseArray) {
if ([GCDAsyncSocket isIPv6Address:addrData]) {
ipv6Addr = [GCDAsyncSocket hostFromAddress:addrData];
}
}
if (ipv6Addr.length == 0) {
ipv6Addr = ipAddr;
}
return ipv6Addr;
}
每次連接socket的時候都將連接的ip和port傳進來贩幻,最后會輸出一個合適的ip轿腺,用這個ip和port進行連接就好了。