首页 > 代码库 > MultipeerConnectivity.framework梳理

MultipeerConnectivity.framework梳理

AirDrop

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

AirDrop实际上是利用Mac与Mac之间的点对点网络来进行的,本质上还是局域网传输,但是不需要路由器或者复杂地手动建立热点了,这一切由系统在后台完成,无需断开当前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 usingWi-Fi and Bluetooth)。具体来说,通过低功耗蓝牙技术(BLE)进行发现(Advertising/Discovery),使用WiFi Direct(P2P WiFi)技术进行数据传输。可参考《iOS 7的AirDrop是利用什么信号来传输的?》《WhatIs 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 YouAround等近场聊天App就是基于Multipeer Connectivity框架实现。

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

(1)双方WiFi和蓝牙都未打开:无法发现。

(2)双方都开启蓝牙:通过蓝牙发现和传输。

(3)双方都开启WiFi:通过WiFi Direct发现和传输,速度接近AirDrop(Reliable速率稍低),不知道同一WLAN下是否优先走局域网?

(4)双方都同时开启了WiFi和蓝牙:应该是模拟AirDrop,通过低功耗蓝牙技术扫描发现握手,然后通过WiFi Direct传输。

 

MultipeerConnectivity.framework

技术分享

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

  • Peer ID‘s allow for uniqueidentification.
  • Advertiser objects tellsothers they‘re available.
  • Browser objects browse foradvertised devices.
  • Session objects handle thecommunications.

This framework is used in twophases: the discovery phase, and the session phase.

 

@class MCPeerID

MCPeerIDrepresents a peer in a multipeer session.

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

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

类似sockaddr,用于标识endpoint,通常是昵称或设备名称。

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

 

@class MCNearbyServiceAdvertiser

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

类似broadcaster

 

@class MCNearbyServiceBrowser

  MCNearbyServiceBrowser looks for nearbypeers, and connects them to sessions.

类似servo listener

 

@class MCSession

  A MCSession facilitates communication amongall peers in a multipeer session.

(MCSession) providesupport for communication between connected peer devices. 

Sessionobjects maintain a set of peer ID objects that represent the peers connected tothe session. 

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

 

@class MCAdvertiserAssistant/MCBrowserViewController

MCAdvertiserAssistant为针对Advertiser封装的管理助手;MCBrowserViewController继承自UIViewController,提供了。

 

Session negotiatation

1.Advertiser initiation

// MCPeerID标识自身

Advertiser::initWithPeer:withDiscoveryInfo:withServiceType

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

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

Advertiser::startAdvertisingPeer

2.Browser initiation

// MCPeerID标识自身

Browser::initWithPeer:withServiceType

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

// let your app search programmatically for nearby devices with appsthat 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.

// Thetimeout parameter is seconds and shouldbe a positive value.

Browser::invitePeer:toSession:withContext:timeout:

类似socket connect

5.Advertiser receive initiation with certificate

// advertiser接收到邀请(未stopAdvertising

Advertiser:didReceiveInvitationFromPeer:withContext:invitationHandler:

{

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

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

// join a session when invited by another peer.

    invitationHandler(YES, session);

}

invitationHandler(YES)类似socket accept

// advertiser收到证书

Advertiser Session::didReceiveCertificate

6.Browser receive acknowledge from advertiser

// browser收到证书

Browser Session::didReceiveCertificate

// browser收到advertiser会话链路established通知

Browser Session::didChangeState(MCSessionStateConnected)

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

7.Advertiser receive acknowledge from browser

// advertiser收到browser会话链路established通知

Advertiser Session::didChangeState(MCSessionStateConnected)

至此,双方通信链路协商成功,可以基于session发送data、resource或stream。

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

 

Session transmission

1.Messages

(1)sendData

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

Session::sendData:toPeers:withMode:error:

// MCSessionsend modes for the -sendData:toPeers:withMode:error: method

typedefNS_ENUM(NSInteger,MCSessionSendDataMode) {

    MCSessionSendDataReliable,     // guaranteed reliable and in-order delivery

   MCSessionSendDataUnreliable    // sentimmediately 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];

//启动发送线程,发送bytestream

[NSOutputStream write];

(2)didReceiveStream(NSInputStream)

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

Session::session:didReceiveStream:(NSInputStream*)streamwithName:fromPeer:

{

//启动接收线程

stream.delegate =self;

           [stream scheduleInRunLoop];

[streamopen];

}

 

//接收回调:NSStreamDelegate

- (void)stream:(NSStream*)aStreamhandleEvent:(NSStreamEvent)eventCode

{

                 switch (eventCode) {

          case NSStreamEventHasBytesAvailable:

             //接收bytestream进行组包

           [NSInputStream read]

              break;

         caseNSStreamEventEndEncountered:

            //接收完成

              break;

         caseNSStreamEventErrorOccurred:

            //接收错误

              break;

 

}

3.Resources

(1)sendResource

//返回NSProgress用于监控进度

Session::sendResourceAtURL:withName:toPeer:withCompletionHandler:

//发送完成时,回调completionHandler

(2)didStartReceivingResource/didFinishReceivingResource

// Startreceiving a resource from remote peer

// NSProgress用于监控进度

Session::session:didStartReceivingResourceWithName:fromPeer:withProgress:

// Finishedreceiving a resource from remote peer and saved the content in a temporarylocation - the app is responsible for moving the file to a permanent locationwithin its sandbox

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

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

 

参考:

使用AirDrop 以无线方式共享内容
Airdropand Multipeer Connectivity
MultipeerConnectivity Framework
理解iOS7的Multipeer Connectivity框架
MultipeerConnectivity点对点连接

《如何使用MultipeerConnectivity》

 

MultipeerConnectivity.framework梳理