一、整体介绍

  • 前面已经介绍了网络访问的NSURLSessionNSURLConnection,还有网页加载有关的webview,基本满足通常的网络相关的开发。
    其实在网络开发中还有比较常用的就是网络状态的检测。苹果对需要联网的应用要求很高,就是必须要进行联网检查。另外,当网络发生异常时能够及时提示用户网络已断开,而不是程序问题造成卡顿;当用户观看视频或下载大文件时,提示用户当前的网络状态为移动流量或wifi下,是否继续使用,以避免在用户不知情下产生过多流量资费等等。

  • 网络状态的检测有多种方法,常用的有三种

二、苹果Reachability使用

使用非常简单,将Reachability.hReachability.m加入项目中,在要使用的地方包含Reachability.h头文件,示例代码:

#import "Reachability.h"

/// 在刚开始就开始监听
- (void)viewDidLoad {
[super viewDidLoad];
// Reachability使用了通知,当网络状态发生变化时发送通知kReachabilityChangedNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appReachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
// 检测指定服务器是否可达
NSString *remoteHostName = @"www.bing.com";
self.hostReachability = [Reachability reachabilityWithHostName:remoteHostName];
[self.hostReachability startNotifier];
// 检测默认路由是否可达
self.routerReachability = [Reachability reachabilityForInternetConnection];
[self.routerReachability startNotifier];
}
/// 当网络状态发生变化时调用
- (void)appReachabilityChanged:(NSNotification *)notification{
Reachability *reach = [notification object];
if([reach isKindOfClass:[Reachability class]]){
NetworkStatus status = [reach currentReachabilityStatus];
// 两种检测:路由与服务器是否可达 三种状态:手机流量联网、WiFi联网、没有联网
if (reach == self.routerReachability) {
if (status == NotReachable) {
NSLog(@"routerReachability NotReachable");
} else if (status == ReachableViaWiFi) {
NSLog(@"routerReachability ReachableViaWiFi");
} else if (status == ReachableViaWWAN) {
NSLog(@"routerReachability ReachableViaWWAN");
}
}
if (reach == self.hostReachability) {
NSLog(@"hostReachability");
if ([reach currentReachabilityStatus] == NotReachable) {
NSLog(@"hostReachability failed");
} else if (status == ReachableViaWiFi) {
NSLog(@"hostReachability ReachableViaWiFi");
} else if (status == ReachableViaWWAN) {
NSLog(@"hostReachability ReachableViaWWAN");
}
} }
}
/// 取消通知
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil];
}

代码中两种检测:默认路由是否可达、服务器是否可达。有很多人可能有疑问,检测是否联网就可以了,怎么还要检测是否服务器可达?默认路由可达?

其实虽然联网了,也不一定能访问外网(通常说的互联网)。比如连了一个路由器,但是路由器没有联网,那么也是不能联网的。还有就是网络数据包在网际层传递时,一个路由传到另一个路由称为一跳,当达到255跳(大部分路由设置为255)还没有传到目的地时,网络数据包则丢弃。

路由器有一套算法来保证路径最优,还有路由表(保存路径表),如果一个数据包在路由表中没有匹配的路径的话,那么路由器就将此数据包发送到默认路由,这里的默认路由就是上面检测的默认路由是否可达。(里面相当复杂,就此打住)

令人崩溃的是:Reachability并不能检测到服务器是否真的可达,只能检测设备是否连接到局域网,以及用的WiFi还是WWAN。即:把设备网络关了,立马检测出NotReachable,连接到路由器立马检测出是ReachableViaWiFi、、、

代码中使用了通知,则释放对象时一定要在dealloc中取消通知。我们知道,通知不能在进程间通信,在哪个线程发送通知则在哪个线程执行。如果想在其它线程监听,则在其它线程调用startNotifier函数,新开启的线程默认都没有开启runloop消息循环,因此还要开启runloop,如下:

    // 被通知函数运行的线程应该由startNotifier函数执行的线程决定
typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSString *remoteHostName = @"www.bing.com";
weakSelf.hostReachability = [Reachability reachabilityWithHostName:remoteHostName];
[weakSelf.hostReachability startNotifier]; weakSelf.routerReachability = [Reachability reachabilityForInternetConnection];
[weakSelf.routerReachability startNotifier];
// 开启当前线程消息循环
[[NSRunLoop currentRunLoop] run];
});

最后,如果想取消检测,调用stopNotifier方法即可

[self.hostReachability stopNotifier];
[self.routerReachability stopNotifier];

三、AFNetworkReachabilityManager使用

  • 直接使用

使用CocoaPods或者直接将AFNetwork下载并添加进项目。如果只是使用AFNetworkReachabilityManager而不适用其它网络功能则只将其.m和.h添加进项目即可。AFNetworkReachabilityManager使用了block的方式,当网络状态发生变化就会调用,且block的调用AFN已经将其限定在主线程下。下面介绍直接使用

#import "AFNetworkReachabilityManager.h"
- (void)afnReachabilityTest {
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
// 一共有四种状态
switch (status) {
case AFNetworkReachabilityStatusNotReachable:
NSLog(@"AFNetworkReachability Not Reachable");
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
NSLog(@"AFNetworkReachability Reachable via WWAN");
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(@"AFNetworkReachability Reachable via WiFi");
break;
case AFNetworkReachabilityStatusUnknown:
default:
NSLog(@"AFNetworkReachability Unknown");
break;
}
}]; [[AFNetworkReachabilityManager sharedManager] startMonitoring];
}
  • 使用AFHTTPSessionManager

当使用AFN网络框架时,大多情况下,我们使用AFNetwork时会创建一个网络中间单例类,以防止换网络框架时要改动太多,比如替换之前用的多的ASI,如果有个中间类的话,替换就很简单,只需要修改中间类即可。使用时调用[NetworkTools sharedManager];即可

/// 头文件
#import "AFHTTPSessionManager.h" @interface NetworkTools : AFHTTPSessionManager
+ (instancetype)sharedManager;
@end --------------------------------------------------------------------------------- /// .m文件
#import "NetworkTools.h" @implementation NetworkTools
+ (instancetype)sharedManager {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
//#warning 基地址
// instance = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.bing.com"]];
instance = [[self alloc] init];
});
return instance;
}
- (instancetype)init {
if ((self = [super init])) {
// 设置超时时间,afn默认是60s
self.requestSerializer.timeoutInterval = 30;
// 响应格式添加text/plain
self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/plain", nil]; // 监听网络状态,每当网络状态发生变化就会调用此block
[self.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusNotReachable: // 无连线
NSLog(@"AFNetworkReachability Not Reachable");
break;
case AFNetworkReachabilityStatusReachableViaWWAN: // 手机自带网络
NSLog(@"AFNetworkReachability Reachable via WWAN");
break;
case AFNetworkReachabilityStatusReachableViaWiFi: // WiFi
NSLog(@"AFNetworkReachability Reachable via WiFi");
break;
case AFNetworkReachabilityStatusUnknown: // 未知网络
default:
NSLog(@"AFNetworkReachability Unknown");
break;
}
}];
// 开始监听
[self.reachabilityManager startMonitoring];
}
return self;
}
@end

四、第三方框架使用

这个使用会更方便一点,有block和通知两种方式,且支持多线程,这里不再详细介绍,README.md有使用方法:

- (void)viewDidLoad {
[super viewDidLoad];
// Allocate a reachability object
Reachability* reach = [Reachability reachabilityWithHostname:@"www.bing.com"]; // Set the blocks
reach.reachableBlock = ^(Reachability*reach) {
// keep in mind this is called on a background thread
// and if you are updating the UI it needs to happen
// on the main thread, like this:
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"REACHABLE!");
});
}; reach.unreachableBlock = ^(Reachability*reach) {
NSLog(@"UNREACHABLE!");
}; // Start the notifier, which will cause the reachability object to retain itself!
[reach startNotifier];
}

问题解决

三种方式差不多,它们在检测设备是否连接局域网和连接方式时很灵敏,但是不能检测服务器是否可达。因为它们底层都是使用了SCNetworkReachabilitySCNetworkReachability发送网络数据包到服务器,但它并不会确认服务器真的收到了此数据包。所以,如果我们想确认是否服务器可达,则需要发送一个真实的网络请求。或者我们使用socket编程,建立一个tcp链接来检测(三次握手成功),只要链接成功则服务器可达。这样只会发送tcpip的报头,数据量最小。如果网络环境差,connect函数会阻塞,所以最后不要在主线程下,调用示例代码,示例如下:

#import <arpa/inet.h>

/// 服务器可达返回true
- (BOOL)socketReachabilityTest {
// 客户端 AF_INET:ipv4 SOCK_STREAM:TCP链接
int socketNumber = socket(AF_INET, SOCK_STREAM, 0);
// 配置服务器端套接字
struct sockaddr_in serverAddress;
// 设置服务器ipv4
serverAddress.sin_family = AF_INET;
// 百度的ip
serverAddress.sin_addr.s_addr = inet_addr("202.108.22.5");
// 设置端口号,HTTP默认80端口
serverAddress.sin_port = htons(80);
if (connect(socketNumber, (const struct sockaddr *)&serverAddress, sizeof(serverAddress)) == 0) {
close(socketNumber);
return true;
}
close(socketNumber);;
return false;
}

iOS Reachability检测网络状态的更多相关文章

  1. iOS开发网络篇—Reachability检测网络状态

    前言:当应用程序需要访问网络的时候,它首先应该检查设备的网络状态,确认设备的网络环境及连接情况,并针对这些情况提醒用户做出相应的处理.最好能监听设备的网络状态的改变,当设备网络状态连接.断开时,程序也 ...

  2. iOS开发 - 检测网络状态(WIFI、2G/3G/4G)

    本文转载至 http://blog.csdn.net/wangzi11322/article/details/45580917 检测网络状态 在网络应用中,需要对用户设备的网络状态进行实时监控,目的是 ...

  3. iOS网络4——Reachability检测网络状态

    一.整体介绍 前面已经介绍了网络访问的NSURLSession.NSURLConnection,还有网页加载有关的webview,基本满足通常的网络相关的开发. 其实在网络开发中还有比较常用的就是网络 ...

  4. Reachability 检测网络状态

    -(void)viewWillAppear:(BOOL)animated { [IOSExcept JudgeNetwork];//联网 NSLog(@"检查网络 请稍后....." ...

  5. iOS中使用 Reachability 检测网络

    iOS中使用 Reachability 检测网络 内容提示:下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测.   写本文的目的 了解Reachability都 ...

  6. iOS开发——网络篇——数据安全(MD5),HTTPS,检测网络状态

    一.数据安全 1.提交用户的隐私数据一定要使用POST请求提交用户的隐私数据GET请求的所有参数都直接暴露在URL中请求的URL一般会记录在服务器的访问日志中服务器的访问日志是黑客攻击的重点对象之一 ...

  7. [iOS 多线程 & 网络 - 2.8] - 检测网络状态

    A.说明 在网络应用中,需要对用户设备的网络状态进行实时监控,有两个目的:(1)让用户了解自己的网络状态,防止一些误会(比如怪应用无能)(2)根据用户的网络状态进行智能处理,节省用户流量,提高用户体验 ...

  8. iOS 检测网络状态 自动判断 认为提示网络改变

    检测网络状态 在网络应用中,需要对用户设备的网络状态进行实时监控,目的是让用户了解自己的网络状态,防止一些误会(比如怪应用无能)根据用户的网络状态进行智能处理,节省用户流量,提高用户体验WIFI\3G ...

  9. 使用 Reachability 获取网络状态

    Reachability source https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Int ...

随机推荐

  1. oracle卸载清除注册表(彻底卸载)

    用Oracle自带的卸载程序不能从根本上卸载Oracle,从而为下次的安装留下隐患,那么怎么才能完全卸载Oracle呢? 那就是直接注册表清除,步骤如下: . 开始->设置->控制面板-& ...

  2. 27、ArrayList和LinkedList的区别

    在Java的List类型集合中,ArrayList和LinkedList大概是最常用到的2个了,细看了一下它们的实现,发现区别还是很大的,这里简单的列一下个人比较关心的区别. 类声明 ArrayLis ...

  3. free -m 内存

    查看内存及交换swap分区大小及使用率 man  free NAME free - Display amount of free and used memory in the system SYNOP ...

  4. 封装UIlabel 辨别用户名 ,话题 ,链接,电话,高亮文字等

    概述 对UIlabel进行封装 用于辨别用户名 ,话题 ,链接,电话,高亮文字等,链接跳转网页,电话点击拨打电话,完美封装UIlabel,适合绝大多数需求 详细 代码下载:http://www.dem ...

  5. (CF#257)B. Jzzhu and Sequences

    Jzzhu has invented a kind of sequences, they meet the following property: You are given x and y, ple ...

  6. TCP Socket 粘包

     这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题.发现自己不是非常清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接: 1.长连接 Client方与Server ...

  7. laravel5.4中{{$name}} 和 {{!! $name !!}} 的区别:后者原生输出。前者转义

  8. 【laravel5.4】自定义公共函数的创建

    原文地址:http://blog.csdn.net/qq_38125058/article/details/76862151 公共函数,简单来说就是在任何地方都可以直接使用这个函数.简单介绍两种实现方 ...

  9. 转载:【微信小程序】 wx:if 与 hidden(隐藏元素)区别

    条件渲染 顾名思义所谓的条件渲染,就是通过条件来判断是否需要渲染该代码块.条件渲染主要是用到wx:if 和 block wx:if 这两个,第一个相信好理解,第二个是在block里面进行条件渲染,这里 ...

  10. PHP-PHP.INI常用配置详解

    variables_order: 假如为'GPCS'表示系统在定义PHP预定义变量时的顺序是GET,POST,COOKIES,SERVER, 此时$_ENV为空数组, 只要把'E'添加到'GPCS'后 ...