美文网首页
局域网通讯

局域网通讯

作者: DDY | 来源:发表于2016-11-03 11:49 被阅读17次

    GameKit-GKPeerPickerController

    • Peer-to-Peer的连接

    Session:会话iPhone通过Session互相发送数据读取数据
    Peer:每一部网络中的设备算一个节点

    第一节 发现其他的节点:
    会话要么把自己当成 服务器/客户端 中的一种,要么做一个节点即当服务器又当客户端

    1. 实现一个Server
      initWithSessionID:displayName:sessionMode:GKSessionModeServer|GKSessionModePeer
      服务器收到客户请求后,回调 session:didReceiveConnectionRequestFromPeer:
      委托类 接受请求
      acceptConnectionFromPeer:error:
      委托类 拒绝请求
      denyConnectionFromPeer:
      成功建立连接后:回调委托类函数:session:peer:didChangeState
    2. 连接到一个服务
      initWithSessionID:displayName:sessionMode: GKSessionModeClient|GKSessionModePeer
      发现可用的服务后,回调委托类函数:session:peer:didChangeState: 提供自己的PeerID
      发送请求:connectToPeer:withTimeout
      成功建立连接:回调:session:peer:didChangeState
    • 交换数据
    1. 发送:
      sendDataToAllPeers:withDataMode:error:
      sendData:toPeer:withDataMode:error
    2. 接受:
      receiveData:fromPeer:inSession:context:
      setDataReceivehandler:withContext:

    第三节
    断开节点:
    disconnectPeerFromAllPeers:
    回调:session:peer:didChangeState:
    第四节 清理:
    移除数据处理器并释放会话

    2.添加一个节点选择器

    1. 创建并初始化一个GKPeerPicerController
      picker = [[GKPeerPickerController alloc] init];
    2. 附加委托
      picker.delegate = self;
    3. 配置可选网络 ( 默认蓝牙 )
      picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby |
      GKPeerPickerConnectionTypeOnline;
    4. 若选择因特网连接,实现:
    • (void)peerPickerController:(GKPeerPickerController *)picker
      didSelectConnectionType:(GKPeerPickerConnectionType)type{
      if (type == GKPeerPickerConnectionTypeOnline) {
      picker.delegate = nil;
      [picker dismiss];
      [picker autorelease];
      //implement your own internet user inter face here
      }
      }
    1. 实现委托的节点选择器
      peerPickerController:(GKPeerPickerControlller )picker
      sessionForConnectionType:(GKPeerPickerConnectionType)type
      {
      GKSession
      session = [[GKSession alloc]] initWithSessionID:myExampleSessionID displayName:myName sessionMode:GKSessionModePeer] ;

    [session autorelease];
    }
    //在覆盖节点选择器的原有方法时实现此方法。

    1. 实现委托的peerPickerController:didConnectPeer:toSession:方法获得对配置好的session的所有权。
      - (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:( NSString *)peerID toSession: (GKSession *)season{
      // 使用Retain过的属性拥有这个session
      self.gameSession = self;
      // 假设我们的对象同样是委托类
      session.delegate = self;
      [session setDataReceiveHandler: self withContext:nil];
      //除掉picker
      picker.delegate = nil;
      [picker dismiss];
      [picker autorelease];
      //开始你的游戏
      }
      7.实现取消连接的代理方法
    • (void) peerPickerControllerDidCancel:(GKPeerPickerController *)picker
      {
      picker.delegate = nil;
      //控制器自动取消对话界面
      [picker autorelease];
      }
    1. 显示对话
      [picker show];

    *使用Sessions

    1. 实现 会话代理的方法:session:didChangeState:
    • (void) session:(GKSession *)session peer:(NSString *)peerID
      didChangeState:(GKPeerConnectionState)state
      {
      switch ( state)
      {
      case GKPeerStateConnecte:
      // 相关代码
      break;
      case GKPeerStateDisconnected:
      //相关代码
      break;
      }
      }
    1. 发送数据到其他Peer
    • (void) mySendDataToPeers: (NSData *)data
      {
      [session sendDataToAllPeers: data withDataMode: GKSendDataReliable error: nil];
      }
    1. 从其他节点接收数据
    • (void) receiveData:(NSData *)data fromPeer: (NSString *)peer inSession:
      (GKSession *)session context:(void *)context
      {
      //读取数据
      }
    1. 清除会话
      [session disconnectFromAllPeers];
      session.availabel = NO;
      [session setDataReceiveHandler: nil withContext: nil];
      session.delegate = nil;
      [session release];

    .

    MultipeerConnectivity

    此框架是在iOS7以后推出,旨在替代GameKit下的GKPeerPickerController

    firechat APP iOS端采用此框架

    FFMCManager.h

    #import <Foundation/Foundation.h>
    #import <MultipeerConnectivity/MultipeerConnectivity.h>
    
    @class FFUser;
    
    @interface FFMCManager : NSObject
    
    /** 是否可以重连 当后台、退出控制器则NO */
    @property (nonatomic, assign) BOOL canInvite;
    /** 用户数组变更 */
    @property (nonatomic, copy) void(^usersArrayChangeBlock)(NSMutableArray *onlineUsersArray);
    
    /** 单例对象 */
    + (instancetype)sharedManager;
    
    /** 初始化 */
    - (instancetype)initWithUser:(FFUser *)user;
    
    /** 重新初始化 */
    - (void)restart;
    
    /** 发送聊天消息给所有用户 */
    - (BOOL)sendMessageToAll:(NSData *)message;
    
    /** 发送聊天消息给指定用户 */
    - (BOOL)sendMessageToUser:(FFUser *)user message:(NSData *)message;
    
    /** 发送资源给指定用户 */
    - (void)sendSourceToPeer:(MCPeerID *)peerID url:(NSURL *)url fileID:(NSString *)fileID result:(void (^)(BOOL success))result;
    
    /** 发送聊天图片给所有用户 */
    - (void)sendImgToAll:(NSURL *)url result:(void (^)(BOOL success))result;
    
    /** 发送聊天图片给指定用户 */
    - (void)sendImgToUser:(FFUser *)user url:(NSURL *)url result:(void (^)(BOOL success))result;
    
    /** 发送头像给所有用户 */
    - (void)sendAvatarToAll;
    
    /** 发送语音给所有用户 */
    - (void)sendVoiceToAll:(NSURL *)url result:(void (^)(BOOL success))result;
    
    /** 发送语音给指定用户 */
    - (void)sendVoiceToUser:(FFUser *)user url:(NSURL *)url result:(void (^)(BOOL success))result;
    
    /** 发送语音给所有用户 */
    - (void)sendVideoToAll:(NSURL *)url result:(void (^)(BOOL success))result;
    
    /** 发送视频给指定用户 */
    - (void)sendVideoToUser:(FFUser *)user url:(NSURL *)url result:(void (^)(BOOL success))result;
    
    @end
    

    FFMCManager.m

    /**
     *  serviceType 命名规则: 由ASCII字母、数字和“-”组成的短文本串,最多15个字符
     *  MCPeerID  代表用户信息
     *  MCSession 启用和管理Multipeer连接会话中的所有人之间的沟通。 通过Sesion发送和读取数据
     *  MCNearbyServiceBrowser 用于搜索附近的服务端,并可以对搜索到的服务端发出邀请加入某个会话中
     *  MCNearbyServiceAdvertiser 接收并处理请求连接的响应。有回调,告知有用户要与服务端设备连接,需自定义提示框及连接处理。
     *  MCAdvertiserAssistant 接收并处理请求连接的响应。无回调,会弹出默认提示框并处理连接。
     *  MCBrowserViewController  用于搜索附近的用户,是基于MCNearbyServiceBrowse的封装
     */
    
    /**
     *  1.通过MCPeer来生成节点信息
     *  2.通过MCNearbyServiceAdvertiser发送广播,告诉别人这里有个节点可连接
     *  3.通过MCNearbyServiceBrowser来搜索服务来找到发送广播的节点,并请求连接
     *  4.当连接成功后便可以通过MCSession来进行消息的发送和读取。
     */
    #import "FFMCManager.h"
    
    @interface FFMCManager ()<MCSessionDelegate, MCNearbyServiceBrowserDelegate, MCNearbyServiceAdvertiserDelegate>
    /** 当前会话 */
    @property (nonatomic, strong) MCSession *session;
    /** 搜索助手 */
    @property (nonatomic, strong) MCNearbyServiceBrowser *browser;
    /** 服务助手 */
    @property (nonatomic, strong) MCNearbyServiceAdvertiser *advertiser;
    /** 用户 */
    @property (nonatomic, strong) MCPeerID *peerID;
    /** 会话锁 */
    @property (nonatomic, strong) NSLock *sessionLock;
    /** 本人 */
    @property (nonatomic, strong) FFUser *localUser;
    /** 用户信息 */
    @property (nonatomic, strong) NSMutableDictionary *usersInfoCache;
    /** 在线用户 */
    @property (nonatomic, strong) NSMutableArray *onlineUsersArray;
    
    @end
    
    @implementation FFMCManager
    
    #pragma mark - 单例对象
    
    static FFMCManager *_instance;
    
    + (instancetype)sharedManager {
        return [[self alloc] init];
    }
    
    + (instancetype)allocWithZone:(struct _NSZone *)zone {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instance = [super allocWithZone:zone];
        });
        return _instance;
    }
    
    - (id)copyWithZone:(NSZone *)zone {
        return _instance;
    }
    
    - (id)mutableCopyWithZone:(NSZone *)zone {
        return _instance;
    }
    
    #pragma mark 初始化
    - (instancetype)initWithUser:(FFUser *)user
    {
        if (self = [super init]) {
            _localUser = user;
            _sessionLock = [[NSLock alloc] init];
            [self restart];
            [self addObserverActive];
        }
        return self;
    }
    
    #pragma mark 定义用户(本人)
    - (void)initLocalUser
    {
        if (_peerID) {
            _peerID = nil;
        }
        _usersInfoCache = [NSMutableDictionary dictionary];
        _onlineUsersArray = [NSMutableArray array];
        _peerID = [[MCPeerID alloc] initWithDisplayName:_localUser.localID];
        [_usersInfoCache setObject:_localUser forKey:_localUser.localID];
    }
    
    #pragma mark 开始会话
    - (void)startSession
    {
        [self stopSession];
        _session = [[MCSession alloc] initWithPeer:_peerID securityIdentity:nil encryptionPreference:MCEncryptionNone];
        _session.delegate = self;
    }
    
    #pragma mark 停止会话
    - (void)stopSession
    {
        if (_session) {
            [_session disconnect];
            _session.delegate = nil;
            _session = nil;
        }
    }
    
    #pragma mark 开始广播
    - (void)startAdvertise
    {
        [self stopAdvertise];
        _localUser.timeStamp = DDYStrFormat(@"%lf",[[NSDate date] timeIntervalSince1970]);
        _advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:_peerID discoveryInfo:_localUser.userInfo serviceType:FFService];
        _advertiser.delegate = self;
        [_advertiser startAdvertisingPeer];
    }
    
    #pragma mark 停止广播
    - (void)stopAdvertise
    {
        if (_advertiser) {
            [_advertiser stopAdvertisingPeer];
            _advertiser.delegate = nil;
            _advertiser = nil;
        }
    }
    
    #pragma mark 开始搜索
    - (void)startBrowse
    {
        [self stopBrowse];
        _browser = [[MCNearbyServiceBrowser alloc] initWithPeer:_peerID serviceType:FFService];
        _browser.delegate = self;
        [_browser startBrowsingForPeers];
    }
    
    #pragma mark 停止搜索
    - (void)stopBrowse
    {
        if (_browser) {
            [_browser stopBrowsingForPeers];
            _browser.delegate = nil;
            _browser = nil;
        }
    }
    
    #pragma mark 重新开始
    - (void)restart
    {
        [self initLocalUser];
        [self startSession];
        [self startBrowse];
        [self startAdvertise];
    }
    
    #pragma mark 邀请用户
    - (void)inviteUser:(MCPeerID *)peerID
    {
        if (_browser) {
            [_browser invitePeer:peerID toSession:_session withContext:nil timeout:0];
        }
    }
    
    #pragma mark 用户加入
    - (void)userJoin:(MCPeerID *)peerID
    {
        DDYInfoLog(@"已经连接");
        [_onlineUsersArray addObject:_usersInfoCache[peerID.displayName]];
        if (self.usersArrayChangeBlock) {
            self.usersArrayChangeBlock(_onlineUsersArray);
        }
    }
    
    #pragma mark 正在进入
    - (void)userConnecting:(MCPeerID *)peerID
    {
        DDYInfoLog(@"正在连接");
    }
    
    #pragma mark 用户离开
    - (void)userLeave:(MCPeerID *)peerID
    {
        DDYInfoLog(@"失去连接");
        [_onlineUsersArray removeObject:_usersInfoCache[peerID.displayName]];
        if (self.usersArrayChangeBlock) {
            self.usersArrayChangeBlock(_onlineUsersArray);
        }
    }
    
    #pragma mark - 发送
    #pragma mark 发送聊天消息给所有用户
    - (BOOL)sendMessageToAll:(NSData *)message
    {
        return [_session sendData:message toPeers:_session.connectedPeers withMode:MCSessionSendDataReliable error:nil];
    }
    
    #pragma mark 发送聊天消息给指定用户
    - (BOOL)sendMessageToUser:(FFUser *)user message:(NSData *)message
    {
        MCPeerID *realPeerID = nil;
        for (MCPeerID *peerID in _session.connectedPeers) {
            if ([peerID.displayName isEqualToString:user.localID]) {
                realPeerID = peerID;
            }
        }
        return realPeerID ? [_session sendData:message toPeers:@[realPeerID] withMode:MCSessionSendDataReliable error:nil] : NO;
    }
    
    #pragma mark 发送资源给指定用户
    - (void)sendSourceToPeer:(MCPeerID *)peerID url:(NSURL *)url fileID:(NSString *)fileID result:(void (^)(BOOL success))result
    {
        NSString *imgName = DDYStrFormat(@"%@<*>%@", fileID, [url lastPathComponent]);
        [_session sendResourceAtURL:url withName:imgName toPeer:peerID withCompletionHandler:^(NSError *error) {
            if (result) result(!error);
        }];
    }
    
    #pragma mark 发送聊天图片给所有用户
    - (void)sendImgToAll:(NSURL *)url result:(void (^)(BOOL success))result
    {
        if (_session.connectedPeers && _session.connectedPeers.count) {
            for (MCPeerID *peerID in _session.connectedPeers) {
                [self sendSourceToPeer:peerID url:url fileID:FFSendImage result:nil];
            }
            if (result) result(YES);
        } else {
            if (result) result(NO);
        }
    }
    
    #pragma mark 发送聊天图片给指定用户
    - (void)sendImgToUser:(FFUser *)user url:(NSURL *)url result:(void (^)(BOOL success))result
    {
        MCPeerID *realPeerID = nil;
        for (MCPeerID *peerID in _session.connectedPeers) {
            if ([peerID.displayName isEqualToString:user.localID]) {
                realPeerID = peerID;
            }
        }
        if (realPeerID) {
            [self sendSourceToPeer:realPeerID url:url fileID:FFSendImage result:^(BOOL success) {
                if (result) result(success);
            }];
        } else {
            if (result) result(NO);
        }
    }
    
    #pragma mark 发送头像给所有用户
    - (void)sendAvatarToAll
    {
        for (MCPeerID *peerID in _session.connectedPeers) {
            [self sendSourceToPeer:peerID url:DDYURLStr(_localUser.avatarPath) fileID:FFSendAvatar result:nil];
        }
    }
    
    #pragma mark 发送语音给所有用户
    - (void)sendVoiceToAll:(NSURL *)url result:(void (^)(BOOL success))result
    {
        if (_session.connectedPeers && _session.connectedPeers.count) {
            for (MCPeerID *peerID in _session.connectedPeers) {
                [self sendSourceToPeer:peerID url:url fileID:FFSendVoice result:nil];
            }
            if (result) result(YES);
        } else {
            if (result) result(NO);
        }
    }
    
    #pragma mark 发送语音给指定用户
    - (void)sendVoiceToUser:(FFUser *)user url:(NSURL *)url result:(void (^)(BOOL success))result
    {
        MCPeerID *realPeerID = nil;
        for (MCPeerID *peerID in _session.connectedPeers) {
            if ([peerID.displayName isEqualToString:user.localID]) realPeerID = peerID;
        }
        if (realPeerID) {
            [self sendSourceToPeer:realPeerID url:url fileID:FFSendVoice result:^(BOOL success) {
                if (result) result(success);
            }];
        } else {
            if (result) result(NO);
        }
    }
    
    #pragma mark 发送语音给所有用户
    - (void)sendVideoToAll:(NSURL *)url result:(void (^)(BOOL success))result
    {
        if (_session.connectedPeers && _session.connectedPeers.count) {
            for (MCPeerID *peerID in _session.connectedPeers) {
                [self sendSourceToPeer:peerID url:url fileID:FFSendVideo result:nil];
            }
            if (result) result(YES);
        } else {
            if (result) result(NO);
        }
    }
    
    #pragma mark 发送视频给指定用户
    - (void)sendVideoToUser:(FFUser *)user url:(NSURL *)url result:(void (^)(BOOL success))result
    {
        MCPeerID *realPeerID = nil;
        for (MCPeerID *peerID in _session.connectedPeers) {
            if ([peerID.displayName isEqualToString:user.localID]) realPeerID = peerID;
        }
        if (realPeerID) {
            [self sendSourceToPeer:realPeerID url:url fileID:FFSendVideo result:^(BOOL success) {
                if (result) result(success);
            }];
        } else {
            if (result) result(NO);
        }
    }
    
    #pragma mark - MCNearbyServiceBrowserDelegate
    #pragma mark Found a nearby advertising peer
    - (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(nullable NSDictionary<NSString *, NSString *> *)info
    {
        if (info) {
            FFUser *user = [FFUser userWithDict:info];
            [_usersInfoCache setObject:user forKey:peerID.displayName];
            if ([info[@"timeStamp"] doubleValue] > [_localUser.userInfo[@"timeStamp"] doubleValue]) {
                [self performSelectorOnMainThread:@selector(inviteUser:) withObject:peerID waitUntilDone:NO];
            }
        }
    }
    
    #pragma mark A nearby peer has stopped advertising
    - (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID
    {
        
    }
    
    #pragma mark Browsing did not start due to an error
    - (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error
    {
        
    }
    
    #pragma mark - MCNearbyServiceAdvertiserDelegate
    #pragma mark Receive Invitation
    - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(nullable NSData *)context invitationHandler:(void (^)(BOOL accept, MCSession *session))invitationHandler
    {
        invitationHandler(YES, _session);
    }
    
    #pragma mark Advertising did not start due to an error.
    - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error
    {
        
    }
    
    #pragma mark - MCSessionDelegate
    #pragma mark Remote peer changed state.
    - (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
    {
        switch (state)
        {
            case MCSessionStateNotConnected:
                [self performSelectorOnMainThread:@selector(userLeave:) withObject:peerID waitUntilDone:NO];
                break;
            case MCSessionStateConnecting:
                [self performSelectorOnMainThread:@selector(userConnecting:) withObject:peerID waitUntilDone:NO];
                break;
            case MCSessionStateConnected:
                [self performSelectorOnMainThread:@selector(userJoin:) withObject:peerID waitUntilDone:NO];
                break;
        }
    }
    
    #pragma mark Received data from remote peer.
    - (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
    {
        
    }
    
    #pragma markReceived a byte stream from remote peer.
    - (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID
    {
        
    }
    
    #pragma mark Start receiving a resource from remote peer.
    - (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
    {
        
    }
    
    #pragma mark receiving a resource from remote peer and saved the content
    - (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(nullable NSError *)error
    {
        
    }
    
    #pragma mark Made first contact with peer and have identity information about the remote peer (certificate may be nil).
    - (void)session:(MCSession *)session didReceiveCertificate:(nullable NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler
    {
        if (certificateHandler) {
            certificateHandler(YES);
        }
    }
    
    #pragma mark 监听挂起和重新进入程序
    #pragma mark 添加监听
    - (void)addObserverActive
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:)
                                                     name:UIApplicationWillResignActiveNotification object:nil]; //监听home键挂起.
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:)
                                                     name:UIApplicationDidBecomeActiveNotification object:nil];  //监听重新进入程序.
    }
    
    #pragma mark 进入前台
    - (void)applicationDidBecomeActive:(UIApplication *)application
    {
        DDYInfoLog( @"[LC_UIApplication] Application did become active." );
        _canInvite = YES;
    }
    
    #pragma mark 挂起程序
    - (void)applicationWillResignActive:(UIApplication *)application
    {
        DDYInfoLog( @"[LC_UIApplication] Application will resign active." );
        _canInvite = NO;
    }
    
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
        [self stopAdvertise];
    }
    
    @end
    

    socket

    http://code.google.com/p/cocoaasyncsocket/

    相关文章

      网友评论

          本文标题:局域网通讯

          本文链接:https://www.haomeiwen.com/subject/pgdputtx.html