afhttprequestoperationmanagerafnetworking支持ipv6 ipv6吗

IOS----轻松掌握AFN网络顶级框架
一、什么是AFN
全称是AFNetworking,是对NSURLConnection的一层封装
虽然运行效率没有ASI高,但是使用比ASI简单
在iOS开发中,使用比较广泛
二、AFN结构
NSURLConnection
AFURLConnectionOperation
AFHTTPRequestOperation
AFHTTPRequestOperationManager(封装了常用的 HTTP 方法)
baseURL :AFN建议开发者针对 AFHTTPRequestOperationManager 自定义个一个单例子类,设置 baseURL, 所有的网络访问,都只使用相对路径即可
requestSerializer :请求数据格式/默认是二进制的 HTTP
responseSerializer :响应的数据格式/默认是 JSON 格式
operationQueue
reachabilityManager :网络连接管理器
manager :方便创建管理器的类方法
HTTPRequestOperationWithRequest :在访问服务器时,如果要告诉服务器一些附加信息,都需要在 Request 中设置
NSURLSession
AFURLSessionManager
AFHTTPSessionManager(封装了常用的 HTTP 方法)
UIKit + AFNetworking 分类
NSProgress :利用KVO
半自动的序列化&反序列化的功能
AFURLRequestSerialization :请求的数据格式/默认是二进制的
AFURLResponseSerialization :响应的数据格式/默认是JSON格式
AFSecurityPolicy
对苹果的网络连接检测做了一个封装
AFNetworkReachabilityManager
三、AFN基本使用
1.AFHTTPSessionManager
是AFN中最重要的对象之一
封装了HTTP请求的常见处理
GET\POST请求
解析服务器的响应数据
创建AFHTTPSessionManager
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
AFHTTPSessionManager的GET\POST请求
// GET请求
& & &http://120.25.226.186:32812/login?username=520it&pwd=520it
& & &第一个参数: 请求的地址 &http://120.25.226.186:32812/login
& & &第二个参数: 请求的参数 &username=520it&pwd=520it
& & &第三个参数: 请求成功的回调
& & &第四个参数: 请求失败的回调
& & &只要利用AFN发送请求, 如果服务器返回的是JSON数据, 那么AFN会自动将JSON转会成OC对象返回给我们
- (NSURLSessionDataTask *)GET:(NSString *)URLString
& & & & & & & & & &parameters:(id)parameters
& & & & & & & & & &success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
& & & & & & & & & &failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
// POST请求
- (NSURLSessionDataTask *)POST:(NSString *)URLString
& & & & & & & & & &parameters:(id)parameters
& & & & & & & & & &success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
& & & & & & & & & &failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
- (void)get2
// 1.创建AFN管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 2.利用AFN管理者发送请求
NSDictionary *params = @{
@&username& : @&520it&,
@&pwd& : @&520it&
[manager GET:@&http://120.25.226.186:32812/login& parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@&请求成功---%@&, responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@&请求失败---%@&, error);
- (void)post2
// 1.创建AFN管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 2.利用AFN管理者发送请求
NSDictionary *params = @{
@&username& : @&520it&,
@&pwd& : @&520it&
[manager POST:@&http://120.25.226.186:32812/login& parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@&请求成功---%@&, responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@&请求失败---%@&, error);
2.AFHTTPRequestOperationManager
创建AFHTTPRequestOperationManager
// 1.创建AFN管理者
// AFHTTPRequestOperationManager内部包装了NSURLConnection
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperationManager的GET\POST请求
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
// POST请求
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
- (void)get
// 1.创建AFN管理者
// AFHTTPRequestOperationManager内部包装了NSURLConnection
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// 2.利用AFN管理者发送请求
NSDictionary *params = @{
@&username& : @&520it&,
@&pwd& : @&520it&
[manager GET:@&http://120.25.226.186:32812/login& parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@&请求成功---%@&, responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@&请求失败---%@&, error);
- (void)post
// 1.创建AFN管理者
// AFHTTPRequestOperationManager内部包装了NSURLConnection
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// 2.利用AFN管理者发送请求
NSDictionary *params = @{
@&username& : @&520it&,
@&pwd& : @&520it&
[manager POST:@&http://120.25.226.186:32812/login& parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@&请求成功---%@&, responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@&请求失败---%@&, error);
四、AFN文件
// 执行下载文件的方法,可以监控下载进度
- (void)downLoadMonitor
// 1.创建网络管理者
// AFHTTPSessionManager 基于NSURLSession
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 2.利用网络管理者下载数据
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@&http://120.25.226.186:32812/resources/videos/minion_02.mp4&]];
destination
- targetPath: 给我们自动写入的文件路径
- block的返回值, 要求返回一个URL, 返回的这个URL就是剪切的位置的路径
completionHandler
- url :destination返回的URL == block的返回的路径
@property int64_t totalUnitC
需要下载文件的总大小
@property int64_t completedUnitC 当前已经下载的大小
NSProgress *progress =
NSURLSessionDownloadTask *downTask = [manager downloadTaskWithRequest:request progress:&progress destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [cachesPath stringByAppendingPathComponent:response.suggestedFilename];
return [NSURL fileURLWithPath:path];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(@&%@&,filePath.absoluteString);
要跟踪进度,需要使用 NSProgress,是在 iOS 7.0 推出的,专门用来跟踪进度的类!
NSProgress只是一个对象!如何跟踪进度!-& KVO 对属性变化的监听!
@property int64_t totalUnitC
@property int64_t completedUnitC
完成单位数
// 给Progress添加监听 KVO
[progress addObserver:self forKeyPath:@&completedUnitCount& options:NSKeyValueObservingOptionNew context:nil];
// 3.启动任务
[downTask resume];
// 收到通知调用的方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(NSProgress *)object change:(NSDictionary *)change context:(void *)context
NSLog(@&%f&,1.0 * pletedUnitCount / object.totalUnitCount);
// 回到主队列刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
self.progress.progress = 1.0 * pletedUnitCount / object.totalUnitC
五、AFN序列化
默认是JSON数据,接收类型是JSON
如果接收的类型和返回的类型不匹配会报错
// 1.创建AFN管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 默认请求二进制
// 默认响应是JSON
// 告诉AFN,支持接受 text/xml 的数据
// [AFJSONResponseSerializer serializer].acceptableContentTypes = [NSSet setWithObject:@&text/xml&];
// 告诉AFN如何解析数据
// 告诉AFN客户端, 将返回的数据当做JSON来处理,默认的是以JSON处理
manager.responseSerializer = [AFJSONResponseSerializer serializer];
// 告诉AFN客户端, 将返回的数据当做XML来处理
manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
// 告诉AFN客户端, 将返回的数据当做而进行来数据 (服务器返回什么就是什么)
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
六、AFN文件上传
// formData: 专门用于拼接需要上传的数据
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
constructingBodyWithBlock:(void (^)(id &AFMultipartFormData& formData))block
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
AFN上传文件代码示例
// 1.创建网络管理者
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 2.利用网络管理者上传数据
NSDictionary *dict = @{@&username&:@&Syl&};
// formData: 专门用于拼接需要上传的数据
[manager POST:@&http://120.25.226.186:32812/upload& parameters:dict constructingBodyWithBlock:
^void(id&AFMultipartFormData& formData) {
Data: 需要上传的数据
name: 服务器参数的名称
fileName: 文件名称
mimeType: 文件的类型
UIImage *image =[UIImage imageNamed:@&minion_02&];
NSData *data = UIImagePNGRepresentation(image);
[formData appendPartWithFileData:data name:@&file& fileName:@&abc.png& mimeType:@&image/png&];
NSURL *url = [NSURL fileURLWithPath:@&/Users/apple/Desktop/CertificateSigningRequest.certSigningRequest&];
// 任意的二进制数据MIMEType application/octet-stream
// [formData appendPartWithFileURL:url name:@&file& fileName:@&abc.cer& mimeType:@&application/octet-stream& error:nil];
[formData appendPartWithFileURL:url name:@&file& error:nil];
} success:^void(NSURLSessionDataTask * task, id responseObject) {
// 请求成功
NSLog(@&请求成功 %@&, responseObject);
} failure:^void(NSURLSessionDataTask * task, NSError * error) {
// 请求失败
NSLog(@&请求失败 %@&, error);
七、监控联网状态
1.AFN监控联网状态
联网状态status
// 2.设置监听
AFNetworkReachabilityStatusUnknown
AFNetworkReachabilityStatusNotReachable
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2,
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
// 提示:要监控网络连接状态,必须要先调用单例的startMonitoring方法
[manager startMonitoring];
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(@&%d&, status);
2.Reachability监控联网状态苹果提供,导入这两个类使用
// 1.检测wifi状态
Reachability *wifi = [Reachability reachabilityForLocalWiFi];
// 2.检测手机是否能上网络(WIFI\3G\2.5G)
Reachability *conn = [Reachability reachabilityForInternetConnection];
// 3.判断网络状态
if ([wifi currentReachabilityStatus] != NotReachable) { // 有wifi
NSLog(@&有wifi&);
} else if ([conn currentReachabilityStatus] != NotReachable) { // 没有使用wifi, 使用手机自带网络进行上网
NSLog(@&使用手机自带网络进行上网&);
} else { // 没有网络
NSLog(@&没有网络&);
①判断联网状态
// [wifi currentReachabilityStatus] != NotReachable
// [conn currentReachabilityStatus] != NotReachable
// 没有用WIFI, 只用了手机网络
// [wifi currentReachabilityStatus] == NotReachable
// [conn currentReachabilityStatus] != NotReachable
// 没有网络
// [wifi currentReachabilityStatus] == NotReachable
// [conn currentReachabilityStatus] == NotReachable
②实时监听网络状态
#import &ViewController.h&
#import &Reachability.h&
@interface HMViewController ()
@property (nonatomic, strong) Reachability *
@implementation HMViewController
- (void)viewDidLoad
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkState) name:kReachabilityChangedNotification object:nil];
self.conn = [Reachability reachabilityForInternetConnection];
[self.conn startNotifier];
- (void)dealloc
[self.conn stopNotifier];
[[NSNotificationCenter defaultCenter] removeObserver:self];
- (void)checkNetworkState
// 1.检测wifi状态
Reachability *wifi = [Reachability reachabilityForLocalWiFi];
// 2.检测手机是否能上网络(WIFI\3G\2.5G)
Reachability *conn = [Reachability reachabilityForInternetConnection];
// 3.判断网络状态
if ([wifi currentReachabilityStatus] != NotReachable) { // 有wifi
NSLog(@&有wifi&);
} else if ([conn currentReachabilityStatus] != NotReachable) { // 没有使用wifi, 使用手机自带网络进行上网
NSLog(@&使用手机自带网络进行上网&);
} else { // 没有网络
NSLog(@&没有网络&);
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'1590人阅读
写的非常详细.原文网址:
自从 5 月初 Apple 明文规定所有开发者在 6 月 1 号以后提交新版本需要支持 IPv6-Only 的网络,大家便开始热火朝天的研究如何支持 IPv6,以及应用中哪些模块目前不支持 IPv6。
一、IPv6-Only 支持是啥?
首先 IPv6,是对 IPv4 地址空间的扩充。目前当我们用 iOS 设备连接上 Wifi、4G、3G 等网络时,设备被分配的地址均是 IPv4 地址,但是随着运营商和企业逐渐部署 IPv6 DNS64/NAT64 网络之后,设备被分配的地址会变成 IPv6 的地址,而这些网络就是所谓的 IPv6-Only 网络,并且仍然可以通过此网络去获取 IPv4 地址提供的内容。客户端向服务器端请求域名解析,首先通过 DNS64 Server 查询 IPv6 的地址,如果查询不到,再向 DNS Server 查询 IPv4
地址,通过 DNS64 Server 合成一个 IPv6 的地址,最终将一个 IPv6 的地址返回给客户端。如图所示:
在 Mac OS 10.11+的双网卡的 Mac 机器(以太网口+无线网卡),我们可以通过模拟构建这么一个 local IPv6 DNS64/NAT64 的网络环境去测试应用是否支持 IPv6-Only 网络,大概原理如下:
参考资料:
二、Apple 如何审核支持 IPv6-Only?
首先第一点: 这里说的支持 IPv6-Only 网络,其实就是说让应用在 IPv6 DNS64/NAT64 网络环境下仍然能够正常运行。但是考虑到我们目前的实际网络环境仍然是 IPv4 网络,所以应用需要能够同时保证 IPv4 和 IPv6 环境下的可用性。从这点来说,苹果不会去扫描 IPv4 的专有 API
来拒绝审核通过,因为 IPv4 的 API 和 IPv6 的 API 调用都会同时存在于代码中。
其次第二点:Apple 官方声明 iOS9 开始向 IPv6 支持过渡,在 iOS9.2+ 支持 IPv4 地址合成 IPv6 地址。其提供的 Reachability 库在 iOS8 系统下,当从 IPv4 切换到 IPv6 网络,或者从 IPv6 网络切换到 IPv4,是无法监控到网络状态的变化。也有一些开发者针对这些
Bug 询问 Apple 的审核部门, 给予的答复是只需要在苹果最新的系统上保证 IPv6 的兼容性即可
最后第三点: 只要应用的主流程支持 IPv6,通过苹果审核即可。对于不支持 IPv6 的模块,考虑到我们现实 IPv6 网络的部署还需要一段时间,短时间内不会影响我们用户的使用。但随着 4G 网络 IPv6 的部署,这部分模块还是需要逐渐安排人力进行支持。
三、应用如何支持 IPv6-Only?
对于如何支持 IPv6-Only,官方给出了如下几点标准:(这里就不对其进行解释了,大家看上面的参考链接即可)
1. Use High-Level Networking F
2. Don’t Use IP Address L
3. Check Source Code for IPv6 DNS64/NAT64 I
4. Use System APIs to Synthesize IPv6 A
3.1 NSURLConnection 是否支持 IPv6?
官方的这句话让我们疑惑顿生:
using high-level networking APIs such as NSURLSession and the CFNetwork
frameworks and you connect by name, you should not need to change anything for your app to work with IPv6 addresses
只说了 NSURLSession 和 CFNetwork 的 API 不需要改变,但是并没有提及到 NSURLConnection。 从上文的参考资料中,我们看到 NSURLSession、NSURLConnection 同属于 Cocoa 的 url loading system,可以猜测出 NSURLConnection 在 iOS9 上是支持 IPv6 的。
应用里面的 API 网络请求,大家一般都会选择 AFNetworking 进行请求发送,由于历史原因,应用的代码基本上都深度引用了 AFHTTPRequestOperation 类,所以目前 API 网络请求均需要通过 NSURLConnection 发送出去,所以必须确认 NSURLConnection 是否支持 IPv6. 经过测试,NSURLConnection 在最新的 iOS9 系统上是支持 IPv6 的。
3.2 Cocoa 的 URL Loading System 从 iOS 哪个版本开始支持 IPv6?
目前我们的应用最低版本还需要支持 iOS7,虽然苹果只要求最新版本支持 IPv6-Only,但是出于对用户负责的态度,我们仍然需要搞清楚在低版本上 URL Loading System 的 API 是否支持 IPv6.
(to fix me, make some experiments)待续~~~
3.3 Reachability 是否需要修改支持 IPv6?
我们可以查到应用中大量使用了 Reachability 进行网络状态判断,但是在里面却使用了 IPv4 的专用 API。
在 Pods:Reachability 中
AF_INET & & & & & & & & &Files:Reachability.m
struct sockaddr_in & & & Files:Reachability.h , Reachability.m
那 Reachability 应该如何支持 IPv6 呢?
(1)目前 Github 的开源库 Reachability 的最新版本是 3.2,苹果也出了一个 Support IPv6 的 Reachability 的官方样例,我们比较了一下源码,跟 Github 上的 Reachability 没有什么差异。
(2)我们通常都是通过一个 0.0.0.0 (ZeroAddress) 去开启网络状态监控,经过我们测试,在 iOS9 以上的系统上 IPv4 和 IPv6 网络环境均能够正常使用;但是在 iOS8 上 IPv4 和 IPv6 相互切换的时候无法监控到网络状态的变化,可能是因为苹果在 iOS8 上还并没有对 IPv6 进行相关支持相关。(但是这仍然满足苹果要求在最新系统版本上支持 IPv6 的网络)。
(3)当大家都在要求 Reachability 添加对于 IPv6 的支持,其实苹果在 iOS9 以上对 Zero Address 进行了特别处理, 是这样的:
reachabilityForInternetConnection: This monitors the address 0.0.0.0,
which reachability treats as a special token that causes it to actually
monitor the general routing status of the device, both IPv4 and IPv6.
+ (instancetype)reachabilityForInternetConnection {
struct sockaddr_in zeroA
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
综上所述,Reachability 不需要做任何修改,在 iOS9 上就可以支持 IPv6 和 IPv4,但是在 iOS9 以下会存在 bug,但是苹果审核并不关心。
四、底层的 socket API 如何同时支持 IPv4 和 IPv6?
由于在应用中使用了网络诊断的组件,大量使用了底层的 socket API,所以对于 IPv6 支持,这块是个重头戏。如果你的应用中使用了长连接,其必然会使用底层 socket API,这一块也是需要支持 IPv6 的。 对于 Socket 如何同时支持 IPv4 和 IPv6,可以参考谷歌的开源库
下面我针对我们的开源 , 说一下是如何同时支持 IPv4 和 IPv6 的。
开源地址:
这个网络诊断组件的主要功能如下:
本地网络环境的监测(本机 IP+本地网关+本地 DNS+域名解析);
通过 TCP Connect 监测到域名的连通性;
通过 Ping 监测到目标主机的连通耗时;
通过 traceRoute 监测设备到目标主机中间每一个路由器节点的 ICMP 耗时;
4.1 IP 地址从二进制到符号的转化
之前我们都是通过 inet_ntoa() 进行二进制到符号,这个 API 只能转化 IPv4 地址。而 inet_ntop() 能够兼容转化 IPv4 和 IPv6 地址。 写了一个公用的 in6_addr 的转化方法如下:
+(NSString *)formatIPv6Address:(struct in6_addr)ipv6Addr{
NSString *address =
char dstStr[INET6_ADDRSTRLEN];
char srcStr[INET6_ADDRSTRLEN];
memcpy(srcStr, &ipv6Addr, sizeof(struct in6_addr));
if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) != NULL){
address = [NSString stringWithUTF8String:dstStr];
4.2 本机 IP 获取支持 IPv6
相当于我们在终端中输入 ifconfig 命令获取字符串,然后对 ifconfig 结果字符串进行解析,获取其中 en0(模拟器)、pdp_ip0(真机)的 ip 地址。
(1)在模拟器和真机上都会出现以 FE80 开头的 IPv6 单播地址影响我们判断,所以在这里进行特殊的处理(当第一次遇到不是单播地址的 IP 地址即为本机 IP 地址)。
(2)在 IPv6 环境下,真机测试的时候,第一个出现的是一个 IPv4 地址,所以在 IPv4 条件下第一次遇到单播地址不退出。
+ (NSString *)deviceIPAdress
while (temp_addr != NULL) {
NSLog(@&ifa_name===%@&,[NSString stringWithUTF8String:temp_addr-&ifa_name]);
// Check if interface is en0 which is the wifi connection on the iPhone
if ([[NSString stringWithUTF8String:temp_addr-&ifa_name] isEqualToString:@&en0&] || [[NSString stringWithUTF8String:temp_addr-&ifa_name] isEqualToString:@&pdp_ip0&])
// 如果是 IPv4 地址,直接转化
if (temp_addr-&ifa_addr-&sa_family == AF_INET){
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr-&ifa_addr)-&sin_addr)];
// & & & & & & & & & &if (address && ![address isEqualToString:@&&] && ![address.uppercaseString hasPrefix:@&FE80&])
// 如果是 IPv6 地址
else if (temp_addr-&ifa_addr-&sa_family == AF_INET6){
address = [self formatIPv6Address:((struct sockaddr_in6 *)temp_addr-&ifa_addr)-&sin6_addr];
if (address && ![address isEqualToString:@&&] && ![address.uppercaseString hasPrefix:@&FE80&])
temp_addr = temp_addr-&ifa_
4.3 设备网关地址获取获取支持 IPv6
其实是在 IPv4 获取网关地址的源码的基础上进行了修改,初开把 AF_INET-&AF_INET6, sockaddr -& sockaddr_in6 之外,还需要注意如下修改,就是拷贝的地址字节数。去掉了 ROUNDUP 的处理。 (解析出来的地址老是少了 4 个字节,结果是偏移量搞错了,纠结了半天),具体参考源码库。
/* net.route.0.inet.flags.gateway */
int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};
if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) & 0) {
address = @&192.168.0.1&;
//for IPv4
for (i = 0; i & RTAX_MAX; i++) {
if (rt-&rtm_addrs & (1 && i)) {
sa_tab[i] =
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa-&sa_len));
sa_tab[i] = NULL;
//for IPv6
for (i = 0; i & RTAX_MAX; i++) {
if (rt-&rtm_addrs & (1 && i)) {
sa_tab[i] =
sa = (struct sockaddr_in6 *)((char *)sa + sa-&sin6_len);
sa_tab[i] = NULL;
4.4 设备 DNS 地址获取支持 IPv6
IPv4 时只需要通过 res_ninit 进行初始化就可以获取,但是在 IPv6 环境下需要通过 res_getservers() 接口才能获取。
+(NSArray *)outPutDNSServers{
res_state res = malloc(sizeof(struct __res_state));
int result = res_ninit(res);
NSMutableArray *servers = [[NSMutableArray alloc] init];
if (result == 0) {
union res_9_sockaddr_union *addr_union = malloc(res-&nscount * sizeof(union res_9_sockaddr_union));
res_getservers(res, addr_union, res-&nscount);
for (int i = 0; i & res-& i++) {
if (addr_union[i].sin.sin_family == AF_INET) {
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN);
NSString *dnsIP = [NSString stringWithUTF8String:ip];
[servers addObject:dnsIP];
NSLog(@&IPv4 DNS IP: %@&, dnsIP);
} else if (addr_union[i].sin6.sin6_family == AF_INET6) {
char ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN);
NSString *dnsIP = [NSString stringWithUTF8String:ip];
[servers addObject:dnsIP];
NSLog(@&IPv6 DNS IP: %@&, dnsIP);
NSLog(@&Undefined family.&);
res_nclose(res);
free(res);
return [NSArray arrayWithArray:servers];
4.4 域名 DNS 地址获取支持 IPv6
在 IPv4 网络下我们通过 gethostname 获取,而在 IPv6 环境下,通过新的 gethostbyname2 函数获取。
phot = gethostbyname(hostN);
phot = gethostbyname2(hostN, AF_INET6);
4.5 ping 方案支持 IPv6
Apple 的官方提供了最新的支持 IPv6 的 ping 方案,参考地址如下:
只是需要注意的是:
(1)返回的 packet 去掉了 IPHeader 部分,IPv6 的 header 部分也不返回 TTL(Time to Live)字段;
(2)IPv6 的 ICMP 报文不进行 checkSum 的处理;
4.6 traceRoute 方案支持 IPv6
其实是通过创建 socket 套接字模拟 ICMP 报文的发送,以计算耗时;
两个关键的地方需要注意:
(1)IPv6 中去掉 IP_TTL 字段,改用跳数 IPv6_UNICAST_HOPS 来表示;
(2)sendto 方法可以兼容支持 IPv4 和 IPv6,但是需要最后一个参数,制定目标 IP 地址的大小;因为前一个参数只是指明了 IP 地址的开始地址。千万不要用统一的 sizeof(struct sockaddr), 因为 sockaddr_in 和 sockaddr 都是 16 个字节,两者可以通用,但是 sockaddr_in6 的数据结构是 28 个字节,如果不显式指定,sendto 方法就会一直返回-1,erroNo 报 22 Invalid argument 的错误。
关键代码如下:(完整代码参考开源组件)
// 构造通用的 IP 地址结构 stuck sockaddr
NSString *ipAddr0 = [serverDNSs objectAtIndex:0];
// 设置 server 主机的套接口地址
NSData *addrData =
BOOL isIPv6 = NO;
if ([ipAddr0 rangeOfString:@&:&].location == NSNotFound) {
isIPv6 = NO;
struct sockaddr_in nativeAddr4;
memset(&nativeAddr4, 0, sizeof(nativeAddr4));
nativeAddr4.sin_len = sizeof(nativeAddr4);
nativeAddr4.sin_family = AF_INET;
nativeAddr4.sin_port = htons(udpPort);
nativeAddr4.sin_addr.s_addr = inet_addr([ipAddr0 UTF8String]);
addrData = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
isIPv6 = YES;
struct sockaddr_in6 nativeAddr6;
memset(&nativeAddr6, 0, sizeof(nativeAddr6));
nativeAddr6.sin6_len = sizeof(nativeAddr6);
nativeAddr6.sin6_family = AF_INET6;
nativeAddr6.sin6_port = htons(udpPort);
inet_pton(AF_INET6, ipAddr0.UTF8String, &nativeAddr6.sin6_addr);
addrData = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
struct sockaddr *
destination = (struct sockaddr *)[addrData bytes];
// 创建 socket
if ((recv_sock = socket(destination-&sa_family, SOCK_DGRAM, isIPv6?IPPROTO_ICMPV6:IPPROTO_ICMP)) & 0)
if ((send_sock = socket(destination-&sa_family, SOCK_DGRAM, 0)) & 0)
// 设置 sender 套接字的 ttl
if ((isIPv6?
setsockopt(send_sock,IPPROTO_IPv6, IPv6_UNICAST_HOPS, &ttl, sizeof(ttl)):
setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) & 0)
// 发送成功返回值等于发送消息的长度
ssize_t sentLen = sendto(send_sock, cmsg, sizeof(cmsg), 0,
(struct sockaddr *)destination,
isIPv6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in));
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:14373次
排名:千里之外
原创:25篇
转载:16篇
(1)(3)(5)(6)(2)(4)(14)(7)

我要回帖

更多关于 阿里云支持ipv6 的文章

 

随机推荐