您的位置:首页 > 理论基础 > 计算机网络

iOS网络编程实践--蓝牙对等网络通信实例讲解

2013-11-24 20:45 375 查看
基于蓝牙对等网络通信就是使用Game Kit中的GKSession、GKSessionDelegate、GKPeerPickerController和GKPeerPickerControllerDelegate来实现。开发过程分为3个步骤:连接、发送数据和接收数据。

下面我们通过一个实例介绍一下基于蓝牙对等网络通信过程。用户点击“连接”按钮,建立连接过程中会出现连接对话框,根据具体情况也会弹出其它的对话框。这些都是针对蓝牙对等网络标准对话框,而Wifi对等网络没有标准对话框可以使用,需要开发者自己实现。当两个设备连接好之后,两个玩家就可以连续轻点“点击”按钮,点击的次数会传递给对方,倒计时时间是30秒。





1、连接

由于对等网络连接过程有点复杂,贯穿了这些协议和类,我们绘制了连接过程的流程图。





下面我们通过代码直接介绍连接流程,其中ViewController.h代码如下:

[java] view
plaincopy

#import <UIKit/UIKit.h>  

  

#import <GameKit/GameKit.h>  

  

   

  

#define  GAMING 0          //游戏进行中  

  

#define  GAMED  1          //游戏结束  

  

   

  

@interface ViewController : UIViewController <GKSessionDelegate, GKPeerPickerControllerDelegate>  

  

{  

  

NSTimer *timer;  

  

}  

  

@property (weak, nonatomic) IBOutlet UILabel *lblTimer;  

  

   

  

@property (weak, nonatomic) IBOutlet UILabel *lblPlayer2;  

  

@property (weak, nonatomic) IBOutlet UILabel *lblPlayer1;  

  

@property (weak, nonatomic) IBOutlet UIButton *btnConnect;  

  

@property (weak, nonatomic) IBOutlet UIButton *btnClick;  

  

   

  

@property (nonatomic, strong) GKPeerPickerController *picker;  

  

@property (nonatomic, strong) GKSession *session;  

  

   

  

- (IBAction)onClick:(id)sender;  

  

- (IBAction)connect:(id)sender;  

  

   

  

//清除UI画面上的数据  

  

-(void) clearUI;  

  

   

  

//更新计时器  

  

-(void) updateTimer;  

  

   

  

@end  

使用Game Kit需要引入头文件<GameKit/GameKit.h>,之前需要把GameKit.framework框架添加到工程中。而且定义类的时候需要实现协议GKSessionDelegate和GKPeerPickerControllerDelegate,并且定义GKPeerPickerController类型的属性picker,定义GKSession类型的属性session。

ViewController.m中创建GKPeerPickerController对象的代码如下:

[java] view
plaincopy

- (IBAction)connect:(id)sender {  

  

_picker = [[GKPeerPickerController alloc] init];  

  

_picker.delegate = self; ①  

  

_picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;  ②  

  

[_picker show];  

  

}  

用户点击的连接按钮时,触发connect:方法。在该方法中创建GKPeerPickerController对象。创建完成不要忘记设置GKPeerPickerController委托为self,第②行代码所示。在第③行代码中connectionTypesMask属性是设置对等网络连接类型,其中有两种类型选择:GKPeerPickerConnectionTypeNearby和GKPeerPickerConnectionTypeOnline,GKPeerPickerConnectionTypeNearby用于蓝牙通讯也是默认的通讯方法,GKPeerPickerConnectionTypeOnline用于Wifi通讯的局域网通讯,这种方式麻烦,需要开发人员自己设计UI画面,自己使用Bonjour服务发现管理连接,以及自己编写输入输出流实现通讯。如果给用户一个选择对话框,代码可以如下编写:

_picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby | GKPeerPickerConnectionTypeOnline;





其中“在线”就是GKPeerPickerConnectionTypeOnline类型,“附近”就是GKPeerPickerConnectionTypeNearby类型。

连接成功之后回调ViewController.m中的回调委托方法peerPickerController:didConnectPeer:toSession:代码:

[java] view
plaincopy

- (void)peerPickerController:(GKPeerPickerController *)pk didConnectPeer:(NSString *)peerID  

  

toSession:(GKSession *) session  

  

{  

  

NSLog(@”建立连接”);  

  

_session = session; ①  

  

_session.delegate = self;  ②  

  

[_session setDataReceiveHandler:self withContext:nil];  ③  

  

_picker.delegate = nil;  

  

[_picker dismiss]; ④  

  

[_btnClick setEnabled:YES];  

  

[_btnConnect setTitle:@"断开连接" forState:UIControlStateNormal];  

  

//开始计时  

  

timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self  

  

selector:@selector(updateTimer)  

  

userInfo:nil repeats:YES]; ⑤  

  

}  

上述代码第①行_session = session将委托方法中返回的会话参数赋值给成员变量,这样我们就获得了一个会话对象。这种方式中,会话ID是应用程序的包ID,如果想自己分配会话ID,可以实现下面委托方法,在方法中使用GKSession的构造方法initWithSessionID:displayName: sessionMode:,自己创建会话对象。

[java] view
plaincopy

- (GKSession *)peerPickerController:(GKPeerPickerController *)picker  

  

sessionForConnectionType:(GKPeerPickerConnectionType)type {  

  

GKSession *session = [[GKSession alloc] initWithSessionID: <自定义SessionID>  

  

displayName:<显示的名字> sessionMode:GKSessionModePeer];  

  

return session;  

  

}  

有的时候会话的状态会发生变化,我们要根据状态的变化做一些UI的清理和资源的释放。监测状态变化在委托方法session:peer:didChangeState:中实现,方法代码如下:

[java] view
plaincopy

- (void)session:(GKSession *)session peer:(NSString *)peerID  

  

didChangeState:(GKPeerConnectionState)state  

  

{  

  

if (state == GKPeerStateConnected)  

  

{  

  

NSLog(@”connected”);  

  

[_btnConnect setTitle:@"断开连接" forState:UIControlStateNormal];  

  

[_btnClick setEnabled:YES];  

  

} else if (state == GKPeerStateDisconnected)  

  

{  

  

NSLog(@”disconnected”);  

  

[self clearUI];  

  

}  

  

}  

其中GKPeerStateConnected常量是已经连接状态,GKPeerStateDisconnected常量是断开连接状态。

2、发送数据

发送数据的代码如下:

[java] view
plaincopy

- (IBAction)onClick:(id)sender {  

  

int count = [_lblPlayer1.text intValue];  

  

_lblPlayer1.text = [NSString stringWithFormat:@"%i",++count];  

  

NSString *sendStr = [NSString  

  

stringWithFormat:@"{\"code\":%i,\"count\":%i}",GAMING,count]; ①  

  

NSData* data = [sendStr dataUsingEncoding: NSUTF8StringEncoding];  

  

if (_session) {  

  

[_session sendDataToAllPeers:data  

  

withDataMode:GKSendDataReliable  error:nil]; ②  

  

}  

  

}  

3、接收数据

为了接收数据首先需要在设置会话时候通过[_session setDataReceiveHandler:self withContext:nil]语句设置接收数据的处理程序是self。这样当数据到达时候就会触发下面的方法特定:

[java] view
plaincopy

- (void) receiveData:(NSData *)data  fromPeer:(NSString *)peer  

  

inSession:(GKSession *)session  context:(void *)context  

  

{  

  

id jsonObj = [NSJSONSerialization JSONObjectWithData:data  

  

options:NSJSONReadingMutableContainers error:nil];  

  

NSNumber *codeObj = [jsonObj objectForKey:@"code"];  

  

if ([codeObj intValue]== GAMING) {  

  

NSNumber * countObj= [jsonObj objectForKey:@"count"];  

  

_lblPlayer2.text = [NSString stringWithFormat:@"%@",countObj];  

  

} else if ([codeObj intValue]== GAMED) {  

  

[self clearUI];  

  

}  

  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: