日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

MultipeerConnectivity框架,近场通信的基本使用

發(fā)布時間:2023/12/19 综合教程 31 生活家
生活随笔 收集整理的這篇文章主要介紹了 MultipeerConnectivity框架,近场通信的基本使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  Multipeer connectivity是一個使附近設(shè)備通過Wi-Fi網(wǎng)絡(luò)、P2P Wi-Fi以及藍(lán)牙個人局域網(wǎng)進(jìn)行通信的框架。互相鏈接的節(jié)點可以安全地傳遞信息、流或是其他文件資源,而不用通過網(wǎng)絡(luò)服務(wù)。此框架是在iOS7以后推出,旨在替代GameKit下的GKPeerPickerController通信。通過此框架我們可以直接連接同一網(wǎng)絡(luò)下的設(shè)備,讓其直接進(jìn)行類似微信,qq那樣的即時通訊效果。

  原理

  其中通訊的原理,是利用節(jié)點來進(jìn)行廣播服務(wù)(標(biāo)示符),其他節(jié)點可以通過服務(wù)(標(biāo)示符)發(fā)現(xiàn)廣播。并對此節(jié)點進(jìn)行連接。在項目中可以將廣播和發(fā)現(xiàn)放在一起實現(xiàn),這樣既可以發(fā)現(xiàn)并連接到其他節(jié)點,同時也可以被其他節(jié)點所搜索鏈接。服務(wù)的命名規(guī)則為由ASCII字母、數(shù)字和“-”組成的短文本串,最多15個字符。通常,一個服務(wù)的名字應(yīng)該由應(yīng)用程序的名字開始,后邊跟“-”和一個獨特的描述符號。

  相關(guān)類

  針對于近場通信,在Multipeer connectivity框架中我們所需要學(xué)習(xí)的類如下:

  1.MCPeerID //代表用戶信息

  2.MCSession //啟用和管理Multipeer連接會話中的所有人之間的溝通。 通過Sesion,給別人發(fā)送和讀取數(shù)據(jù)。

  3.MCNearbyServiceBrowser //用于搜索附近的服務(wù)端,并可以對搜索到的服務(wù)端發(fā)出邀請加入某個會話中。

  4.MCNearbyServiceAdvertiser //廣播服務(wù)可以接收,并處理用戶請求連接的響應(yīng)。但是,這個類會有回調(diào),告知有用戶要與服務(wù)端設(shè)備連接,需要自定義提示框,以及自定義連接處理。

  5.MCAdvertiserAssistant //廣播服務(wù)可以接收,并處理用戶請求連接的響應(yīng)。沒有回調(diào),會彈出默認(rèn)的提示框,并處理連接。

  6.MCBrowserViewController //用于搜索附近的用戶,是基于MCNearbyServiceBrowse的封裝

  使用步驟

MCPeerID,MCSession,MCNearbyServiceAdvertiser,MCNearbyServiceBrowser本文中用這四個類來實現(xiàn)(MCNearbyServiceAdvertiser,MCNearbyServiceBrowserx相對來說更原生態(tài),此處通過這個兩個類來編寫代碼更容易幫助我們理解其內(nèi)部實現(xiàn)的過程)。

通過MCPeer來生成節(jié)點信息,
通過MCNearbyServiceAdvertiser來發(fā)送廣播,告訴別人這里有個節(jié)點可連接,其他節(jié)點想要發(fā)現(xiàn)此節(jié)點必須
通過MCNearbyServiceBrowser來搜索服務(wù)(標(biāo)示符)來找到發(fā)送廣播的節(jié)點,并請求連接,
當(dāng)連接成功后便可以通過MCSession來進(jìn)行消息的發(fā)送和讀取。

  為了方便理解筆者此處將程序分為服務(wù)端(發(fā)送服務(wù))和客戶端(搜索服務(wù))。無論是在服務(wù)端還是在客戶端其節(jié)點信息的配置和消息池的原理都相同,下面是具體的實現(xiàn)過程

  代碼實戰(zhàn)

  通用部分

 a. 配置服務(wù)標(biāo)示符

1 //近場通訊標(biāo)識符(相當(dāng)于頻段號)
2 static NSString * const ServiceType = @"nearByContent";

  b.創(chuàng)建節(jié)點信息和消息池

  在這里我們需要先通過MCPeerID創(chuàng)建節(jié)點信息(一般為個人設(shè)備信息)。并設(shè)置MCSession來控制其數(shù)據(jù)通信。

1 //創(chuàng)建用戶消息和廣播消息池
2 self.peerID = [[MCPeerID alloc] initWithDisplayName:[UIDevice currentDevice].name];
3 self.session = [[MCSession alloc] initWithPeer:self.peerID];
4 //配置消息池代理
5 self.session.delegate = self;

  由于MCSession的代理方法較多,筆者會在項目端再做說明,下面來看看每個項目端的實現(xiàn)

  服務(wù)端實現(xiàn)

  a.創(chuàng)建一個服務(wù)端項目,在storyBoard中配置如下界面,并將兩個BarButtonItem(廣播,停止廣播)和發(fā)送消息按鈕分別實現(xiàn)點擊方法

    

 1 /**
 2  *  廣播方法
 3  */
 4 - (IBAction)startAdvertiser:(UIBarButtonItem *)sender {
 5     [self.advertiser startAdvertisingPeer];
 6     NSLog(@"開啟廣播");
 7 }
 8 /**
 9  *  停止廣播方法
10  */
11 - (IBAction)stopAdvertiser:(UIBarButtonItem *)sender {
12     [self.advertiser stopAdvertisingPeer];
13     NSLog(@"關(guān)閉廣播");
14     //關(guān)閉時需要關(guān)閉通道
15     [self.writeStream close];
16     [self.readStream close];
17     //從消息循環(huán)池中移除
18     [self.writeStream removeFromRunLoop:[NSRunLoop mainRunLoop]  forMode:NSDefaultRunLoopMode];
19     [self.readStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
20     [self.session disconnect];
21 }
22 /**
23  *  消息發(fā)送方法
24  */
25 - (IBAction)sendMsg:(UIButton *)sender {
26 }

  b.在對應(yīng)的viewController中配置屬性

 1 /**  近場客戶 */
 2 @property (nonatomic, strong) MCNearbyServiceBrowser *browser;
 3 /**  近場客戶消息池 */
 4 @property (nonatomic, strong) MCSession *session;
 5 /**  個人信息 */
 6 @property (nonatomic, strong) MCPeerID *peerID;
 7 /**  輸出流 */
 8 @property (nonatomic, strong) NSOutputStream *writeStream;
 9 /**  輸入流 */
10 @property (nonatomic, strong) NSInputStream *readStream;
11 /**  存放廣播端數(shù)組 */
12 @property (nonatomic, strong) NSMutableArray *dataSource;
13 /**  鏈接狀態(tài)文本 */
14 @property (weak, nonatomic) IBOutlet UILabel *stateLabel;
15 /**  消息顯示文本 */
16 @property (weak, nonatomic) IBOutlet UILabel *msgLabel;
17 /**  消息編輯框 */
18 @property (weak, nonatomic) IBOutlet UITextField *msgTextField;

  c.創(chuàng)建對應(yīng)的廣播對象MCNearbyServiceAdvertiser

 1 - (MCNearbyServiceAdvertiser *)advertiser {
 2     if (_advertiser == nil) {
 3         _advertiser = ({
 4             //其中discoveryInfo是展示給Browser端查看的信息可設(shè)為nil
 5             MCNearbyServiceAdvertiser *advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID discoveryInfo:nil serviceType:ServiceType];
 6             advertiser.delegate = self;
 7             advertiser;
 8         });
 9     }
10     return _advertiser;
11 }

  當(dāng)創(chuàng)建好廣播對象中只需要在對應(yīng)的地方開啟廣播或停止廣播即可,如上a.步驟中代碼所示,開啟廣播后若接收到其他節(jié)點的鏈接請求會觸發(fā)廣播對象的代理方法

 1 /**
 2  *  接收到客戶端要求鏈接消息時調(diào)用
 3  *
 4  *  @param advertiser        服務(wù)端廣播
 5  *  @param peerID            客戶端信息
 6  *  @param context           請求內(nèi)容
 7  *  @param invitationHandler 是否接受鏈接回調(diào)函數(shù)
 8  */
 9 - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession * _Nonnull))invitationHandler {
10     //一般服務(wù)端不會拒絕鏈接所以此處直接鏈接所有客戶端
11     //同意鏈接并加入廣播組消息池
12     invitationHandler(YES,self.session);
13 }

  在同意其加入后服務(wù)端的消息池就會開始嘗試和客戶端的消息池建立鏈接。建立鏈接時便會回調(diào)MCSession的代理方法

 1 /**
 2  *  消息池連通狀態(tài)改變時調(diào)用
 3  *
 4  *  @param session 消息池
 5  *  @param peerID  節(jié)點信息
 6  *  @param state   消息池連通狀態(tài)
 7  */
 8 - (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
 9     switch (state) {
10         case MCSessionStateConnecting:
11             NSLog(@"正在鏈接至:%@",peerID.displayName);
12             break;
13         case MCSessionStateConnected:{
14             NSLog(@"與%@建立鏈接",peerID.displayName);
15             [self.dataSource addObject:peerID];
16             //鏈接成功后創(chuàng)建輸出流
17             NSError *error;
18             self.writeStream = [self.session startStreamWithName:@"adverting" toPeer:peerID error:&error];
19             if (error) {
20                 NSLog(@"輸出流創(chuàng)建失敗");
21             }
22             //將輸出流通道打開,并加入消息循環(huán)池
23             [self.writeStream open];
24             [self.writeStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
25             //展示鏈接狀態(tài)
26             dispatch_async(dispatch_get_main_queue(), ^{
27                 self.stateLabel.text = @"已連接";
28             });
29         }
30             break;
31         case MCSessionStateNotConnected:{
32             NSLog(@"與%@無連接",peerID.displayName);
33             [self.dataSource removeObject:peerID];
34             dispatch_async(dispatch_get_main_queue(), ^{
35                 self.stateLabel.text = @"未連接";
36             });
37         }
38             break;
39         default:
40             break;
41     }
42 }

  d.當(dāng)消息池狀態(tài)為鏈接時便可開始發(fā)送消息,發(fā)送消息的方法分為3種:

  1.直接發(fā)送二進(jìn)制數(shù)據(jù)

1 //二進(jìn)制文件傳輸方法
2 [self.session sendData:[self.msgTextField.text dataUsingEncoding:NSUTF8StringEncoding] toPeers:self.dataSource withMode:MCSessionSendDataReliable error:&error];

  當(dāng)消息池接收到消息后會回調(diào)MCSession的代理方法

 1 /**
 2  *  接收到二進(jìn)制數(shù)據(jù)時調(diào)用
 3  *
 4  *  @param session 信息池
 5  *  @param data    二進(jìn)制數(shù)據(jù)
 6  *  @param peerID  節(jié)點信息
 7  */
 8 - (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
 9     //獲取傳輸數(shù)據(jù)
10     NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
11     dispatch_async(dispatch_get_main_queue(), ^{
12         //展示數(shù)據(jù)
13         self.msgLabel.text = text;
14     });
15 }

  2.通過輸入輸出流來發(fā)送二進(jìn)制數(shù)據(jù)

  輸出流的創(chuàng)建已在消息池鏈接狀態(tài)回調(diào)函數(shù)中寫出,此處便不再多說,當(dāng)創(chuàng)建好輸出流后,對應(yīng)的鏈接的消息池會接受到輸入流的鏈接,其MCSession回調(diào)函數(shù)為

 1 /**
 2  *  接受到數(shù)據(jù)流事件請求時調(diào)用
 3  *
 4  *  @param session    信息池
 5  *  @param stream     輸入數(shù)據(jù)流
 6  *  @param streamName 數(shù)據(jù)流名字
 7  *  @param peerID     節(jié)點信息
 8  */
 9 - (void)    session:(MCSession *)session
10    didReceiveStream:(NSInputStream *)stream
11            withName:(NSString *)streamName
12            fromPeer:(MCPeerID *)peerID {
13     //打開請求的輸入流通道,加入消息循環(huán)池
14     [stream open];
15     [stream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
16     //設(shè)置代理,以接收數(shù)據(jù)
17     stream.delegate = self;
18     //持有該輸入流
19     self.readStream = stream;
20 }

  當(dāng)輸入輸出流都鏈接完成并打開通道加入消息循環(huán)池后便可以開始利用輸入輸出流來進(jìn)行數(shù)據(jù)通信,輸入輸出流的數(shù)據(jù)通信在前面的博客(http://www.cnblogs.com/purple-sweet-pottoes/p/4856955.html)中已有列出,此處不再贅述。

  3.通過文件url地址,直接發(fā)送文件

  關(guān)于文件的發(fā)送其實也和前面差不讀,筆者此處直接貼出對應(yīng)方法

 1 //MCSession發(fā)送文件方法   
 2 -  (void)sendResourceAtURL:(NSURL *)resourceURL
 3                                   withName:(NSString *)resourceName
 4                                     toPeer:(MCPeerID *)peerID
 5                      withCompletionHandler:(nullable void (^)(NSError * __nullable error))completionHandler
 6 
 7 //MCSeesion收到文件時的回調(diào)方法
 8 - (void)                    session:(MCSession *)session
 9   didStartReceivingResourceWithName:(NSString *)resourceName
10                            fromPeer:(MCPeerID *)peerID
11                        withProgress:(NSProgress *)progress;
12 - (void)                    session:(MCSession *)session
13  didFinishReceivingResourceWithName:(NSString *)resourceName
14                            fromPeer:(MCPeerID *)peerID
15                               atURL:(NSURL *)localURL
16                           withError:(nullable NSError *)error;

  到這里服務(wù)端的實現(xiàn)已經(jīng)基本完成。

  客戶端的實現(xiàn)

  客戶端的實現(xiàn)路數(shù)基本同服務(wù)端相同,唯一有所不同的是服務(wù)端創(chuàng)建的是廣播對象,而在客戶端是創(chuàng)建搜索服務(wù)對象  

1 - (MCNearbyServiceBrowser *)browser {
2     if (_browser == nil) {
3         _browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID serviceType:ServiceType];
4         _browser.delegate = self;
5     }
6     return _browser;
7 }

  對應(yīng)將廣播和停止廣播方法改為掃描和斷開服務(wù)(由于代碼相同便不再注釋)

 1 - (IBAction)startSearchAdver:(UIBarButtonItem *)sender {
 2     [self.browser startBrowsingForPeers];
 3 }
 4 - (IBAction)stopConnectAdver:(UIBarButtonItem *)sender {
 5     [self.browser stopBrowsingForPeers];
 6     [self.writeStream close];
 7     [self.readStream close];
 8     [self.writeStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
 9     [self.readStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
10     [self.session disconnect];
11 }

  當(dāng)掃描到對應(yīng)的服務(wù)節(jié)點后,便會回調(diào)掃描對象的代理方法

1 - (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary<NSString *,NSString *> *)info {
2     //請求鏈接到對應(yīng)的服務(wù)節(jié)點
3     [browser invitePeer:peerID toSession:self.session withContext:nil timeout:30];
4     NSLog(@"發(fā)現(xiàn)%@廣播,正在鏈接...",peerID.displayName);
5 }

  其他部分對應(yīng)服務(wù)端代碼來編寫即可!

  效果圖:

  1.未廣播服務(wù)和掃描服務(wù)時狀態(tài)

    

  2.開啟廣播和開始掃描服務(wù)后狀態(tài)

  

  3.狀態(tài)鏈接便可以開始點對點通信

  

  4.任意端斷開服務(wù)后,其消息池都會斷開鏈接,若要重新發(fā)送消息需要重新進(jìn)行鏈接

  關(guān)于近場通信的基本使用就講到這里,如其中有何錯誤之處請指出,謝謝!最后祝大家新年快樂!

  

總結(jié)

以上是生活随笔為你收集整理的MultipeerConnectivity框架,近场通信的基本使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。