http://blog.csdn.net/phunxm/article/details/43450167

AirDrop

苹果在2010推出的OS X 10.7 Lion系统中加入了全新的AirDrop功能,该功能允许两台Mac机之间无线传输文件。区别于传统的局域网文件共享方式,AirDrop不要求两台机器在同一个网络内。用户无需设置,只需要打开AirDrop文件夹即可查看到其他用户,分享文件变得非常便捷。

AirDrop不需要基于(无线)路由器或者手动建立热点组网,它是利用Mac与Mac之间的点对点网络来进行会话传输。这一切由系统在后台完成,无需断开当前WiFi网络,也不影响当前连接WiFi网络的通信,就可以与其他Mac通过内置特定信道通信。

WWDC13上推出的iOS7也开始支持iOS设备之间使用AirDrop实现共享传输。关于AirDrop的条件要求及内部机制,可参考《为什么iOS 7 和 OS X 之间的AirDrop 不能互传?》。

WWDC14推出的OS X 10.10 Yosemite操作系统,终于打通了与iOS移动设备之间的跨平台AirDrop传输。运行Mac OS X Yosemite 10.10版本的Mac设备(型号≥2012)和运行iOS 7及以上的iOS设备(≥iPhone5,≥iPad 4,iPad mini,≥iPod touch)之间才能实现跨平台文件传输。

根据官方资料显示,AirDrop基于蓝牙和WiFi实现(AirDrop does the rest using Wi-Fi and Bluetooth)。具体来说,通过低功耗蓝牙技术(BLE)进行发现(Advertising/Browsing),使用WiFi Direct(P2P WiFi)技术进行数据传输。可参考《iOS 7的AirDrop是利用什么信号来传输的?》《What Is AirDrop? How Does It Work?》。因此,开启AirDrop不要求双方必须联网或连接到同一局域网,但必须同时打开WiFi和蓝牙,且进行传输的两台设备必须保持在9米的范围之内。

Multipeer Connectivity

在iOS7中,引入了一个全新的框架——Multipeer Connectivity(多点连接)。利用Multipeer Connectivity框架,即使在没有连接到WiFi(WLAN)或移动网络(xG)的情况下,距离较近的Apple设备(iMac/iPad/iPhone)之间可基于蓝牙和WiFi(P2P WiFi)技术进行发现和连接实现近场通信。

Multipeer Connectivity扩充的功能与利用AirDrop传输文件非常类似,可以将其看作AirDrop不能直接使用的补偿,代价是需要自己实现。手机不联网也能跟附近的人聊得火热的FireChat和See You Around等近场聊天App、近距离无网遥控交互拍照神器拍咯App就是基于Multipeer Connectivity框架实现。

相比AirDrop,Multipeer Connectivity在进行发现和会话时并不要求同时打开WiFi和蓝牙,也不像AirDrop那样强制打开这两个开关,而是根据条件适时选择使用蓝牙或(和)WiFi。粗略测试情况如下:

  • 双方WiFi和蓝牙都未打开:无法发现。
  • 双方都开启蓝牙:通过蓝牙发现和传输。
  • 双方都开启WiFi:通过WiFi Direct发现和传输,速度接近AirDrop(Reliable速率稍低),不知道同一WLAN下是否优先走局域网?
  • 双方都同时开启了WiFi和蓝牙:应该是模拟AirDrop,通过低功耗蓝牙技术扫描发现握手,然后通过WiFi Direct传输。

MultipeerConnectivity.framework

以下是MultipeerConnectivity.framework的四个核心对象:

  • Peer ID's allow for unique identification.
  • Advertiser objects tells others they're available.
  • Browser objects browse for advertised devices.
  • Session objects handle the communications.

@class MCPeerID

MCPeerID represents a peer in a multipeer session.

Peer IDs (MCPeerID) uniquely identify an app running on a device to nearby peers.

provide information that identifies the device and its user to other nearby devices.

类似sockaddr,用于标识连接的两端endpoint,通常是昵称或设备名称。

该对象只开放了displayName属性,私有MCPeerIDInternal对象持有的设备相关的_idString/_pid64字段并未公开。

在许多情况下,客户端同时广播并发现同一个服务,这将导致一些混乱,尤其是在client/server模式中。所以,每一个服务都应有一个类型标示符——serviceType,它是由ASCII字母、数字和“-”组成的短文本串,最多15个字符。

@class MCNearbyServiceAdvertiser

MCNearbyServiceAdvertiser advertises availability of the local peer, and handles invitations from nearby peers.

类似broadcaster。

  • 主线程(com.apple.main-thread(serial))创建MCNearbyServiceAdvertiser并启动startAdvertisingPeer。
  • MCNearbyServiceAdvertiserDelegate异步回调(didReceiveInvitationFromPeer)切换回主线程。
  • 在主线程didReceiveInvitationFromPeer中创建MCSession并invitationHandler(YES, session)接受会话连接请求(accept参数为YES)。

@class MCNearbyServiceBrowser

MCNearbyServiceBrowser looks for nearby peers, and connects them to sessions.

类似servo listen+client connect。

  • 主线程(com.apple.main-thread(serial))创建MCNearbyServiceBrowser并启动startBrowsingForPeers。
  • MCNearbyServiceBrowserDelegate异步回调(foundPeer/lostPeer)切换回主线程。
  • 主线程创建MCSession并启动invitePeer。

@class MCSession

A MCSession facilitates communication among all peers in a multipeer session.

(MCSession) provide support for communication between connected peer devices(identified by MCPeerID).

Session objects maintain a set of peer ID objects that represent the peers connected to the session.

注意,peerID并不具备设备识别属性。

类似TCP链接中的socket。创建MCSession时,需指定自身MCPeerID,类似bind。

为避免频繁的会话数据通知阻塞主线程,MCSessionDelegate异步回调(didChangeState/didReceiveCertificate/didReceiveData/didReceiveStream)有一个专门的回调线程——com.apple.MCSession.callbackQueue(serial)。为避免阻塞MCSeesion回调线程,最好新建数据读(写)线程!

@class MCAdvertiserAssistant/MCBrowserViewController

MCAdvertiserAssistant为针对Advertiser封装的管理助手;MCBrowserViewController继承自UIViewController,提供了基本的UI应用框架。

MCBrowser/MCAdvertiser的回调线程一般是delegate所在线程Queue:com.apple.main-thread(serial)。

==================================================

Session negotiation

1.Advertiser initiation

// MCPeerID标识自身,discoveryInfo为广播信息。

Advertiser::initWithPeer:withDiscoveryInfo:withServiceType


// 启动广播(定时广播)

// tell nearby peers that your app is willing to join sessions of a specified type.

Advertiser::startAdvertisingPeer

2.Browser initiation

// MCPeerID标识自身

Browser::initWithPeer:withServiceType


//启动扫描/搜索,搜索到Advertiser后,回调browser:foundPeer

// let your app search programmatically for nearby devices with apps that support sessions of a particular type.

Browser::startBrowsingForPeers

类似socket(SO_BROADCAST)的listen。

3.Browser found advertiser

//搜索到advertiser,可以发出会话邀请建立连接

Browser::browser:foundPeer:withDiscoveryInfo:

4.Browser invite advertiser

//向advertiser发出会话邀请协商建立通道,类似TCP三次握手中的<SYN>

//需要基于自身MCPeerID创建specifiedMCSession

// creates a session and invite other peers to join it.

// The timeout parameter is seconds and should be a positive value.

Browser::invitePeer:toSession:withContext:timeout:

类似socket connect。

// 与peer的session会话链路首先收到connecting通知

Browser Session::didChangeState(MCSessionStateConnecting)

5.Advertiser receive initiation with certificate

// advertiser接收到邀请(未stopAdvertising)

Advertiser:didReceiveInvitationFromPeer:withContext:invitationHandler:

{

// advertiser接受邀请,类似TCP三次握手中的<SYN,ACK>

//需要基于自身MCPeerID创建specified MCSession

// join a session when invited by another peer.

invitationHandler(YES, session);

}

invitationHandler(YES)类似socket accept。

// 与peer的session会话链路首先收到connecting通知

Advertiser Session::didChangeState(MCSessionStateConnecting)


//与peer的session会话链路收到证书

Advertiser Session::didReceiveCertificate

6.Browser receive acknowledge from advertiser

//与peer的session会话链路收到证书

Browser Session::didReceiveCertificate


//与peer的session会话链路收到connected通知

Browser Session::didChangeState(MCSessionStateConnected)


// browser底层可能再给advertiser发送一个<ACK>包?

7.Advertiser receive acknowledge from browser

//与peer的session会话链路收到connected通知

Advertiser Session::didChangeState(MCSessionStateConnected)

至此,双方通信链路协商成功,可以基于session(connect self and peer)向peer发送data、resource或stream。

该框架内部自行维持Session Keep-Alive,具体不可考。注意可能存在的会话过期和配对问题。

以下为典型Browser-Advertiser发现、握手流程:

可能存在中间人攻击(man-in-the-middle attacks):

Sender(Browser) startBrowsingForPeers,中间人(MitM)同时开启Browsing/Advertising模式。

①Receiver(Advertiser) startAdvertisingPeer。

②MitM Browser嗅探到接收Advertiser的广播报文(discoveryInfo&serviceType,可能加密或完全裸露)。

③MitM Advertiser原封不动广播透传嗅探到的接收Advertiser的广播报文(discoveryInfo&serviceType)。

④发送Browser有50%概率扫描到MitM Advertiser,误认为接收Advertiser。

⑤发送Browser邀请伪装的MitM Advertiser加入会话(invitePeer with Context,可能加密或完全裸露)。

⑥伪装的MitM Browser透传context邀请接收Advertiser加入会话(invitePeer with Context)。

⑦⑧⑨⑩攻击者与通信的两端同时建立起独立的会话(Browser-MitM[Advertiser/Browser]-Advertiser),透传发送Browser和接收Advertiser之间的所有数据。

如未加密,整个过程中的数据将被中间人完全窃取,还可能插入新的内容。

MitM攻击解决方案:

核心思路是在打破或限制MitM与Browser/Advertiser两端建立连接,例如发现Advertiser立即锁定,减少MitM Browser透传Advertising报文给Browser的几率,从而减少或避免Browser发现MitM Advertiser。

另外,应增加Browser发起会话(InvitePeer)的身份标识,从而减少MitM Browser伪造Invite报文的几率。

以上过程1~3步中,由于在启动AirDrop之前没有可预知匹配的设备标识属性(例如uuid、MAC地址),广播发现是完全公开透明的,MitM是不可避免的。

发送方或接收方创建MCSession的接口为initWithPeer:securityIdentity:encryptionPreference:

  • 若参数2指定加密(MCEncryptionRequired),可避免报文泄露,但是会降低传输效率,且无法阻止中间人完全透传。
  • 若参数1指定Security Identity提供local peer's identity,则可基于PKI对会话握手过程进行身份甄别,但是广播前需要提前交换pubKey,这对于无网场景无疑是一大挑战。或者可基于某一闭环体系内可识别的身份校验体制?

受邀请方接受邀请(invitationHandler:YES)后,彼此都会收到对方的证书(didReceiveCertificate:fromPeer),可通过PKI校验机制,从而鉴别peer的身份。

==================================================

Session transmission

1.Messages

(1)sendData

//发送数据(可发给多个MCPeerID)

Session::sendData:toPeers:withMode:error:

// MCSession send modes for the -sendData:toPeers:withMode:error: method

typedefNS_ENUM(NSInteger,MCSessionSendDataMode) {

MCSessionSendDataReliable,     // guaranteed reliable and in-order delivery

MCSessionSendDataUnreliable    // sent immediately without queuing, no guaranteed delivery

} NS_ENUM_AVAILABLE(10_10,7_0);

类似socket的两种类型:SOCK_STREAM/SOCK_DGRAM?

(2)didReceiveData

//接收数据(可能有多个MCPeerID/MCSession)

Session::session:didReceiveData:fromPeer:

2.Streams

(1)startStream(NSOutputStream)

// streamName可预埋length

NSOutputStream* outStream = Session::startStreamWithName:toPeer:error:

[outStream open];

// 启动发送线程(写数据线程),发送byte stream

if( [outStream hasSpaceAvailable] ) { // 检查流中是否还有可供写入的空间

[outputStream write];// 将buffer中的字节流数据写入流中

}

为保证数据发送的实时性,写数据线程一直while(1)轮询队列中是否有数据要发送。

(2)didReceiveStream(NSInputStream)

MCSession底层收到数据流后,其回调线程为com.apple.MCSession.callbackQueue(serial)。

如果在该回调线程中直接做数据收割处理,则可能阻塞该回调线程,导致无法及时获取其他的数据流通知。因此,需要新建一个读数据线程(调用[[NSRunLoop currentRunLoop] run]激活循环loop,闲时休眠)。

当收到数据流回调didReceiveStream时,将inputStream添加到读数据线程RunLoop的事件源中,在下一个loop,回调NSStreamDelegate,对相应NSStreamEvent进行处理。

// 同一InputStream可能多次接收回调,可提取对比streamName中的length,以判定接收完成

Session::session:didReceiveStream:(NSInputStream*)inputStream withName:fromPeer:

{

//设置代理

inputStream.delegate =self;

//调用performSelector将以下代码块切换到读数据线程执行:

{

//将该对象分配一个run loop接收stream events

[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]

//启动接收

[inputStream open];

}

}

//接收回调:NSStreamDelegate

- (void)stream:(NSStream*)inputStream handleEvent:(NSStreamEvent)eventCode

{

switch (eventCode) {

case NSStreamEventHasBytesAvailable:

//从inputstream拷贝字节流数据到buffer中进行组包

[inputStream read];

break;

case NSStreamEventEndEncountered: //接收完成

case NSStreamEventErrorOccurred: //接收错误

[inputStream close];

[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[inputStream release];

break;

}

}

3.Resources

(1)sendResource

//返回NSProgress用于监控进度

Session::sendResourceAtURL:withName:toPeer:withCompletionHandler:

//发送完成时,回调completionHandler

(2)didStartReceivingResource/didFinishReceivingResource

// Start receiving a resource from remote peer

// NSProgress用于监控进度

Session::session:didStartReceivingResource WithName:fromPeer:withProgress:

// Finished receiving a resource from remote peer and saved the content in a temporary location - the app is responsible for moving the file to a permanent location within its sandbox

//接收完成,需从临时localURL移动文件至永久位置

- (void)session:didFinishReceivingResourceWithName:fromPeer:atURL:withError:

以下为典型Browser-Advertiser会话传输流程:

参考:

《使用AirDrop 以无线方式共享内容》
《Airdropand Multipeer Connectivity》

《MultipeerConnectivity Framework》

《理解iOS7的Multipeer Connectivity框架》

《MultipeerConnectivity点对点连接》

《如何使用MultipeerConnectivity》

《Send the Monkey a Message with Multipeer Connectivity》

《Nayaksb/Airdrop-MultipeerConnectivity》

《Multipeer Connectivity Follow Up》

《Certificate in iOS MCSession》

MultipeerConnectivity.framework梳理相关推荐

  1. MultipeerConnectivity.framework框架

    AirDrop 苹果在2010推出的OS X 10.7 Lion系统中加入了全新的AirDrop功能,该功能允许两台Mac机之间无线传输文件.区别于传统的局域网文件共享方式,AirDrop不要求两台机 ...

  2. iOS- 蓝牙集成GameKit,MultipeerConnectivity,CoreBluetooth

    参考博客http://www.cnblogs.com/kenshincui/p/4220402.html#bluetooth 忙中偷闲,看到上面博客不错,正想没接触过蓝牙,话说好记性不如烂笔头,于是参 ...

  3. 蓝牙框架之MultipeerConnectivity框架

    蓝牙框架之MultipeerConnectivity框架 前面已经说了GameKit相关的蓝牙操作类从iOS7已经全部过期,苹果官方推荐使用MultipeerConnectivity代替.但是应该了解 ...

  4. 01-iOS蓝牙开发简介

    蓝牙开发简介 1.1-iOS蓝牙实现方案 iOS中提供了4个框架用于实现蓝牙连接 1.<GameKit.framework>:用法非常简单 只能用于iOS设备之间的连接,多用于蓝牙对战的游 ...

  5. iOS之深入解析操作系统的架构

    一.iOS 系统架构层次 在 iOS 中,框架是一个目录,包含了共享资源库,用于访问该资源库中储存的代码的头文件,以及图像.声音文件等其它资源.共享资源库定义应用程序可以调用的函数和方法. iOS 为 ...

  6. iOS开发 蓝牙技术4.0详解

    前言 前端时间,同学在做项目过程中遇到关于蓝牙方面的问题,今天我就给大家进行详细的进行讲解下蓝牙在iOS开发中的具体实现.在介绍蓝牙前,大家要搞清楚什么是蓝牙? 什么是蓝牙? 随着蓝牙低功耗技术BLE ...

  7. iOS操作系统的层次架构和相关服务

    Cocoa Touch Layer(触摸UI层).MediaLayer(媒体层).CoreServices Layer(核心服务层).Core OS Layer(核心OS层). CocoaTouch ...

  8. iOS总体框架介绍和详尽说明

    总体介绍 iOS为应用程序开发提供了许多可使用的框架,并构成IOS操作系统的层次架构,分为四层,从上到下依次为:Cocoa Touch Layer(触摸UI层).MediaLayer(媒体层).Cor ...

  9. iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook系统服务开发汇总...

    iOS开发过程中有时候难免会使用iOS内置的一些应用软件和服务,例如QQ通讯录.微信电话本会使用iOS的通讯录,一些第三方软件会在应用内发送短信等.今天将和大家一起学习如何使用系统应用.使用系统服务: ...

最新文章

  1. magento获取判断当前页或句柄handles
  2. 脑与认知科学3 脑神经影像下
  3. openssl php api,PHP7使用openssl解密易班API中的用户数据
  4. poj3279 反转 挑战程序设计竞赛
  5. 企业级市场,正成为IT老兵创业的最佳选择
  6. js正则匹配闭合标签_正则表达式匹配封闭html标签
  7. 设计素材|美丽的几何和多边形背景纹理
  8. Ansible(三)编写ansible的playbook文件(实现端口更改、远程主机信息采集、负载均衡)
  9. dist文件夹、src文件夹、dest文件夹作用
  10. XenServer 6.5实战系列之六:Creating a Storage Repository (CIFS)
  11. 管鲍计算机教室管理系统,管鲍多媒体电子教室
  12. redis锁的几种实现
  13. 学习python的感受
  14. python实现微信自动投票_Python——开发一个自动化微信投票器【附代码实例方法】...
  15. python批量处理图片属性_python PIL 批量处理处理图片
  16. elementUI动态菜单
  17. 微信屏蔽抖音?扎克伯格登报发表道歉信
  18. 如何在EXCEL中画横线并输入汉字
  19. O2O优惠券使用新人赛数据发掘工程
  20. 你好,李焕英!贾玲痛哭,一句话戳痛2.3亿中国人

热门文章

  1. 安装HTC VIVE COSMOS软件安装完成,缺少各种dll文件
  2. PHP str_replace() 函数 替换字符串中的一些字符
  3. [笔记分享] [GPIO] MSM8x39 GPIO 硬件部分小结
  4. ffmpeg命令分析-tee输出多路流
  5. 微服务系列:分布式文件存储之 MinIO 入门指南
  6. 微信公众号、小程序使用注意事项
  7. STM32F4xx实现接入Internet的“基石”——PartA
  8. Echarts 散点象限图(二)动态绘制
  9. Android 屏幕录像教程
  10. 领取奖品html页面,我的奖品.html