一、整体介绍

  • 前面已经介绍了网络访问的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;
}

示例代码下载

在github下载

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

  1. iOS中使用 Reachability 检测网络

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

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

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

  3. 【开发记录】iOS中使用 Reachability 检测网络

    如果你想在iOS程序中提供一仅在wifi网络下使用(Reeder),或者在没有网络状态下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测. 写本文的目的 了解Re ...

  4. iOS中使用 Reachability 检测网络区分手机网络类型 WiFi 和2 3 4 G

    如果你想在iOS程序中提供一仅在wifi网络下使用(Reeder),或者在没有网络状态下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测. 写本文的目的 了解Re ...

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

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

  6. 李洪强iOS开发之使用 Reachability 检测网络

    1.iOS平台是按照一直有网络连接的思路来设计的,开发者利用这一特点创造了很多优秀的第三方应用. 大多数的iOS应用都需要联网,甚至有些应用严重依赖网络,没有网络就无法正常工作. 2.在你的应用尝试通 ...

  7. iOS开发 - Swift实现检测网络连接状态及网络类型

    一.前言 在移动开发中,检测网络的连接状态尤其检测网络的类型尤为重要.本文将介绍在iOS开发中,如何使用Swift检测网络连接状态及网络类型(移动网络.Wifi). 二.如何实现 Reachabili ...

  8. ios开发利用AFN检测网络状态

    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager]; [manager setRe ...

  9. iOS开发 利用Reachability判断网络环境

    导入头文件:#import "Reachability.h" 然后将 SystemConfiguration.framework 添加进工程: 1.检查当前的网络状态(wifi.W ...

随机推荐

  1. [BOT] 一种android中实现“圆角矩形”的方法

    内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...

  2. Apache Ignite之集群应用测试

    集群发现机制 在Ignite中的集群号称是无中心的,而且支持命令行启动和嵌入应用启动,所以按理说很简单.而且集群有自动发现机制感觉对于懒人开发来说太好了,抱着试一试的心态测试一下吧. 在Apache ...

  3. Asp.net Boilerplate源码中NotNullAttribute的用处

    看Asp.net Boilerplate 1.1.3.0源码时发现有一个NotNullAttribute的定义和27处的引用,就是不知道它的作用,当然顾名思义是可以的,就是不知道它是怎么判断的,在哪里 ...

  4. windows环境下sublime的nodejs插件详细安装图解

    前面的话   搜索了好多文档后,才成功地安装了sublime text3的nodejs插件.为了存档,也为了方便有同样需求的朋友,将其安装过程详细记录如下 安装nodejs 虽然nodejs官网提供了 ...

  5. ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法

    在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...

  6. 初步认识TDD

    TDD,测试驱动开发(Test Driven Development)是极限编程中倡导的程序开发方法,以其倡导先写测试程序,然后编码实现其功能得名.本文将对TDD有一个较为系统的认识.    基础属性 ...

  7. 套用JQuery EasyUI列表显示数据、分页、查询

    声明,本博客从csdn搬到cnblogs博客园了,以前的csdn不再更新,朋友们可以到这儿来找我的文章,更多的文章会发表,谢谢关注! 有时候闲的无聊,看到extjs那么肥大,真想把自己的项目改了,最近 ...

  8. MCDownloadManager ios文件下载管理器

    我们用AFNetworking小试牛刀,写一个简单的下载器来演示功能. 前言 为什么AFNetworking能够成为顶级框架?我们究竟该如何领悟它的精髓所在?这都是很难的问题.安全,高效,流畅,这3个 ...

  9. jquery实现下拉框多选

    一.说明 本文是利用EasyUI实现下拉框多选功能,在ComboxTree其原有的基础上对样式进行了改进,样式表已上传demo,代码如下 二.代码 <!DOCTYPE html PUBLIC & ...

  10. SQL 约束

    先用设计器创建约束.再用代码创建约束.数据库约束是为了保证数据的完整性(正确性)而实现的一套机制见文件Employee.sql非空约束(选择复选框)主键约束(PK) primary key const ...