iOS Wi-Fi
查漏补缺集是自己曾经做过相关的功能,但是重做相关功能或者重新看到相关功能的实现,感觉理解上更深刻。这一类的文章集中记录在查漏补缺集。
iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可能是与WiFi相关的。
1.Ping域名、Ping某IP
有时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作。这里的ping与传统的做get或者post请求还是有很大区别的。比如我们连接了某个WiFi,测试ping www.baidu.com,如果能ping 通,基本可以断定可以上网了,但是如果我们做了一个get 请求(url 是www.baidu.com),路由器可能重定向这个WiFi内的某网页了,依然没有错误返回,就会误认为可以正常上网。
这里有关于ping命令的详细解释:百度百科Ping
iOS中想要ping域名或者ip,苹果提供了一个官方例子SimplePing
在例子中,有一个苹果已经封装过的类【SimplePing.h】和【SimplePing.m】
使用起来也相当的简单:
首先创建一个Ping对象:
1
2
3
4
5
|
SimplePing *pinger = [[SimplePing alloc] initWithHostName:self.hostName]; self.pinger = pinger; pinger.delegate = self; pinger.addressStyle = SimplePingAddressStyleICMPv4; [pinger start]; |
然后在start成功的代理方法中,发送数据报文:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * start成功,也就是准备工作做完后的回调 */ - (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address { // 发送测试报文数据 [self.pinger sendPingWithData:nil]; } - (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error { NSLog(@ "didFailWithError" ); [self.pinger stop]; } |
其他几个代理方法也非常简单,就简单记录一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 发送测试报文成功的回调方法 - (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber { NSLog(@ "#%u sent" , sequenceNumber); } //发送测试报文失败的回调方法 - (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error { NSLog(@ "#%u send failed: %@" , sequenceNumber, error); } // 接收到ping的地址所返回的数据报文回调方法 - (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber { NSLog(@ "#%u received, size=%zu" , sequenceNumber, packet.length); } - (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet { NSLog(@ "#%s" ,__func__); } |
注意点:
iOS 中 ping失败后(即发送测试报文成功后,一直没后收到响应的报文),不会有任何回调方法告知我们。而一般ping 一次的结果也不太准确,ping 花费的时间也非常短,所以我们一般会ping多次,发送一次ping 测试报文0.5s后检测一下这一次ping是否已经收到响应。0.5s后检测时,如果已经收到响应,则可以ping 通;如果没有收到响应,则视为超时。
做法也有很多种,可以用NSTimer或者 {- (void)performSelector: withObject:afterDelay:}
这里有一个别人写的工程:https://github.com/lovesunstar/STPingTest
PingTest效果图
终端ping效果图
2.获取WiFi信息
以前物联网刚火的时候,出现过很多一体式无线路由,所以App里难免会遇到要判断当前所连接的WiFi,以及获取WiFi信息的功能。13年的时候查过一些关于WiFi的方法,后面渐渐都忘记了。惭愧!!!
需要添加SystemConfiguration.framework 并在当前类中添加代码#import
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//获取WiFi 信息,返回的字典中包含了WiFi的名称、路由器的Mac地址、还有一个Data(转换成字符串打印出来是wifi名称) - (NSDictionary *)fetchSSIDInfo { NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfaces(); if (!ifs) { return nil; } NSDictionary *info = nil; for (NSString *ifnam in ifs) { info = (__bridge_transfer NSDictionary *)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam); if (info && [info count]) { break ; } } return info; } //打印出来的结果: 2016-05-12 15:28:51.674 SimplePing[18883:6790207] WIFI_INFO:{ BSSID = "a4:2b:8c:c:7f:bd" ; SSID = bdmy06; SSIDDATA = ; } |
3.获取WiFi名称
有了上一步,获取WiFi名称就非常简单了。
1
2
3
|
NSString *WiFiName = info[@ "SSID" ]; //打印结果: 2016-05-12 15:35:13.059 SimplePing[18887:6791418] bdmy06 |
完整的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
- (NSString *)fetchWiFiName { NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfaces(); if (!ifs) { return nil; } NSString *WiFiName = nil; for (NSString *ifnam in ifs) { NSDictionary *info = (__bridge_transfer NSDictionary *)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam); if (info && [info count]) { // 这里其实对应的有三个key:kCNNetworkInfoKeySSID、kCNNetworkInfoKeyBSSID、kCNNetworkInfoKeySSIDData, // 不过它们都是CFStringRef类型的 WiFiName = [info objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID]; // WiFiName = [info objectForKey:@"SSID"]; break ; } } return WiFiName; } |
4.获取当前所连接WiFi的网关地址
例如自己家的路由器一般默认的网关地址是192.168.1.1,获取的就是这个192.168.1.1。
为什么不直接写死呢?
因为一些商场或者有多个路由器的网关地址是不一样的,比如之前有个公司的网关是192.168.89.1。
这里有篇博客,这是地址
需要导入的库:
1
|
#import #import #import |
获取网关的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
- (NSString *)getGatewayIpForCurrentWiFi { NSString *address = @ "error" ; struct ifaddrs *interfaces = NULL; struct ifaddrs *temp_addr = NULL; int success = 0; // retrieve the current interfaces - returns 0 on success success = getifaddrs(&interfaces); if (success == 0) { // Loop through linked list of interfaces temp_addr = interfaces; //*/ while (temp_addr != NULL) { /*/ int i=255; while ((i--)>0) //*/ if (temp_addr->ifa_addr->sa_family == AF_INET) { // Check if interface is en0 which is the wifi connection on the iPhone if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@ "en0" ]) { // Get NSString from C String //ifa_addr //ifa->ifa_dstaddr is the broadcast address, which explains the "255's" // address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]; address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; //routerIP----192.168.1.255 广播地址 NSLog(@ "broadcast address--%@" ,[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]); //--192.168.1.106 本机地址 NSLog(@ "local device ip--%@" ,[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]); //--255.255.255.0 子网掩码地址 NSLog(@ "netmask--%@" ,[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)]); //--en0 端口地址 NSLog(@ "interface--%@" ,[NSString stringWithUTF8String:temp_addr->ifa_name]); } } temp_addr = temp_addr->ifa_next; } } // Free memory freeifaddrs(interfaces); in_addr_t i = inet_addr([address cStringUsingEncoding:NSUTF8StringEncoding]); in_addr_t* x = &i; unsigned char *s = getdefaultgateway(x); NSString *ip=[NSString stringWithFormat:@ "%d.%d.%d.%d" ,s[0],s[1],s[2],s[3]]; free(s); return ip; } |
其中 getdefaultgateway 是一个C语言文件中的方法,在工程里可以找到。
5.获取本机在WiFi环境下的IP地址
获取本机在WiFi环境下的ip地址,在上一节中其实已经写过,这里将其提取出来即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
- (NSString *)getLocalIPAddressForCurrentWiFi { NSString *address = nil; struct ifaddrs *interfaces = NULL; struct ifaddrs *temp_addr = NULL; int success = 0; // retrieve the current interfaces - returns 0 on success 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) { // Check if interface is en0 which is the wifi connection on the iPhone if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@ "en0" ]) { address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; return address; } } temp_addr = temp_addr->ifa_next; } freeifaddrs(interfaces); } return nil; } |
同样的方式也可以获取广播地址、子网掩码、端口等,组装成一个字典。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
- (NSMutableDictionary *)getLocalInfoForCurrentWiFi { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; struct ifaddrs *interfaces = NULL; struct ifaddrs *temp_addr = NULL; int success = 0; // retrieve the current interfaces - returns 0 on success 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) { // Check if interface is en0 which is the wifi connection on the iPhone if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@ "en0" ]) { //----192.168.1.255 广播地址 NSString *broadcast = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]; if (broadcast) { [dict setObject:broadcast forKey:@ "broadcast" ]; } NSLog(@ "broadcast address--%@" ,broadcast); //--192.168.1.106 本机地址 NSString *localIp = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; if (localIp) { [dict setObject:localIp forKey:@ "localIp" ]; } NSLog(@ "local device ip--%@" ,localIp); //--255.255.255.0 子网掩码地址 NSString *netmask = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)]; if (netmask) { [dict setObject:netmask forKey:@ "netmask" ]; } NSLog(@ "netmask--%@" ,netmask); //--en0 端口地址 NSString *interface = [NSString stringWithUTF8String:temp_addr->ifa_name]; if (interface) { [dict setObject:interface forKey:@ "interface" ]; } NSLog(@ "interface--%@" ,interface); return dict; } } temp_addr = temp_addr->ifa_next; } } // Free memory freeifaddrs(interfaces); return dict; } |
将返回的字典打印出来:
1
2
3
4
5
6
|
2016-05-12 17:59:09.257 SimplePing[19141:6830567] wifi:{ broadcast = "192.168.1.255" ; interface = en0; localIp = "192.168.1.7" ; netmask = "255.255.255.0" ; } |
iOS Wi-Fi的更多相关文章
- Redpine Signals RS9110-N-11-02 Wi-Fi解决方案
Redpine Signals公司的RS9110-N-11-02是兼容IEEE 802.11bgn的Wi-Fi客户端模块,集成了MAC,基带处理器,RF收发器和功率放大器.和RS9110-LI MAC ...
- IOS开发-几种截屏方法
IOS开发-几种截屏方法 1. UIGraphicsBeginImageContextWithOptions(pageView.page.bounds.size, YES, zoomSc ...
- iOS开发-正则表达式3种形式
转至:http://www.cnblogs.com/GarveyCalvin/p/4250145.html iOS开发-正则表达式的使用方法 前 言:在表单验证中,我们经常会使用到正则,因为我们需要用 ...
- IOS开发-OC学习-常用功能代码片段整理
IOS开发-OC学习-常用功能代码片段整理 IOS开发中会频繁用到一些代码段,用来实现一些固定的功能.比如在文本框中输入完后要让键盘收回,这个需要用一个简单的让文本框失去第一响应者的身份来完成.或者是 ...
- IOS开发-UI学习-sqlite数据库的操作
IOS开发-UI学习-sqlite数据库的操作 sqlite是一个轻量级的数据库,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了,而且它的处理速度比Mysql.PostgreSQL这 ...
- iOS开发-多线程开发之线程安全篇
前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象.同一个变量.同一个文件和同一个方法等.因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安 ...
- iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)
简介 在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间 ...
- iOS开发-Swift获取手机设备信息(UIDevice)
使用UiDevice获取设备信息 获取设备名称 let name = UIDevice.currentDevice().name 获取设备系统名称 let systemName = UIDevice. ...
- IOS 网络-深入浅出(一 )-> 三方SDWebImage
首要我们以最为常用的UIImageView为例介绍实现原理: 1)UIImageView+WebCache: setImageWithURL:placeholderImage:options: 先显 ...
随机推荐
- Javascript.Reactjs-5-prop-validation-and-proptypes
Props & PropTypes 1. Props "Props are the mechanism React uses to let components communicat ...
- Java中四种引用:强、软、弱、虚引用
这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173 Java中四种引用:强.软.弱.虚引用 1.1.强引用当我们使用new 这个关键字创建对象时 ...
- Getting Started With Hazelcast 读书笔记(第四章)
第四章 分而治之 在指导了如何进行基本使用之后,又再次进入理论模块. Hazelcast的基本策略就是切片分区,默认是271个片.内置一个 partition table记录那个节点是那个分区,并在h ...
- 为什么不能访问django自带的索引页
通过HTTP://192.168.160.128:8000访问虚拟机上的django索引页出现“ 无法访问此网站 192.168.160.128 拒绝了我们的连接请求. ” 是什么原因呢?费了好大一番 ...
- c# 导出数据到Excel模板
最近在做一个发邮件的功能,客户要求需要导出一个Excel附件,并给了附件的格式, eg: Last Name 姓 First Name 名 Chinese Characters汉字书写(仅大陆人填写) ...
- 【java】:常用工具类
PS; 平时用到的一些工具类,验证非空.字符切割.时间转换.金额转换 package com.jws.common.util; import java.io.UnsupportedEncodingEx ...
- 类Collections的静态方法的使用(代码)
package cn.itcast.p2.toolclass.collections.demo; import java.util.ArrayList; import java.util.Collec ...
- 使用C#代码部署SharePoint 2013开发包简单总结(一)
这篇文章将总结下如何将自己开发的列表.Web部件.事件接收器等元素部署到SharePoint的服务器.因水平有限,我的做法未必是最佳实践,会有些错误理解和疏漏,欢迎各位高手批评指正——但一定要能给出更 ...
- serialize data use msgpack
#ifndef _BYTEBUFFER_H #define _BYTEBUFFER_H #include <msgpack.hpp> typedef unsigned char uint8 ...
- SRETAN
SRETAN (sretan.pas/c/cpp) 题目描述 4和7是幸运数字,输入k,输出第k个只含有4和7的数. 输入格式 一行一个数k 输出格式 一行一个数表示答案 样例输入 3 样例输出 44 ...