В статье рассказывается как реализовать связь нескольких устройств по сети (Wi-Fi или Bluetooth) с помощью GameKit и GKSession. Так как мы используем GameKit, можно сказать что эта статья еще и и о том, как сделать мультиплеер в играх. Для этих же целей можно использовать NSNetService и NSNetServiceBrowser, но они работают как-то странно и не всегда находят устройства в сети, да и поддержку Bluetooth в iOS 5 в NSNetService убрали.

Общие сведения о GKSession

При соеденении через GKSession, iOS сама определяет через что лучше связаться с другим устройством (Bluetooth или Wi-Fi). Но, конечно, можно самому вручную регулировать способ связи, например, включить только Bluetooth и выключить Wi-Fi.

Что же такое GKSession? GKSession — это класс, который выполняет функции поиска других устройств и отправку данных к ним, а так же прием данных с других устройств. GKSession может работать в трех режимах — client, server, peer. Также, GKSession имеет делегат через который уведомляет нас о происходящих событиях.

В режиме Server GKSession позволяет подключать к себе другие устройства, которые работают в режиме Client. Устройства, которые работают в режиме Client не могут «разговаривать» друг с другом, они могут только взаимодействовать с «сервером».

В режиме peer нет центрального устройства с которым связываются все остальные. В такой ситуации каждый сам себе и сервер и клиент для других. В этой статье мы рассмотрим именно такой принцип работы.

В GKSession устройства называются peer и имеют свой ID. Чтобы преобразовать ID пира в «человеческое» имя используется метод:

- (NSString *)displayNameForPeer:(NSString *)peerID;

Состояния устройств

Каждое устройство использующее GKSession имеет определенное состояние. Разберемся в них:

  • GKPeerStateAvailable — устройство, которое еще не подключено к сессии, к нему можно подключится
  • GKPeerStateUnavailable — устройство, связь с которым прервалась
  • GKPeerStateConnected — подключенное устройство
  • GKPeerStateDisconnected — устройство, которое отключилось само
  • GKPeerStateConnecting — устройство подключается, если имеет такое состояние

GKSessionDelegate

Как было сказано выше, GKSession имеет делегат GKSessionDelegate. Рассмотрим его методы:

- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state;

Уведомляет нас о том, что устройство (peer) peerID сменило свое состояние на state.

- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID;

Вызывается, когда устройство peerID хочет к нам подключится. Мы можем принять подключение так:

NSError* error = nil;  

[session acceptConnectionFromPeer:peerID error:&error];

Либо отказать в подключении:

  [session denyConnectionFromPeer:peerID];

Методы, которые сообщают об ошибках:

- (void)session:(GKSession *)session connectionWithPeerFailed:(NSString *)peerID withError:(NSError *)error;

- (void)session:(GKSession *)session didFailWithError:(NSError *)error;

Также, есть еще метод в который приходят данные от других устройств:

- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context

Тут data — данные которые к нам пришли. Peer — от кого пришли.

GKSession в действии

Чтобы создать сессию нужно выполнить:

GKSession* session = [[GKSession alloc] initWithSessionID:@"session_id" displayName:nil sessionMode:GKSessionModePeer];

session.delegate = self;
[session setDataReceiveHandler:self withContext:NULL];
session.available = YES;

С помощью @»session_id» устройства узнают друг друга. Чтобы устройства нашли друг друга этот параметр должен быть одинаковый. DisplayName — это имя, которое будут видеть другие устройства, если задать nil — будет использоваться название устройства (то, которое мы можем получить из UIDevice).

После того, как сессия создана уведомления о состоянии устройств мы будем получать в метод:

- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {

// в зависимости от state решаем, что делать с пиром. Например, можем подключить его:
if ( state == GKPeerStateAvailable ) {
[session connectToPeer:peerID withTimeout:10.0];
}
}

Чтобы отправить данные какому-либо пиру мы можем сделать так:

 NSData* data; // данные для отправки

NSArray* peers; // ID пиров, кому отправляем
NSError* error; // ошибка, если будет
[session sendData:data toPeers:peers withDataMode:GKSendDataReliable error:&error];

Тут следует уделить внимание режиму отправки, их два:

  • GKSendDataReliable — гарантированная доставка данных, большие порции данных нужно разбивать на более мелкие, может приостановится, если будут неполадки с сетью
  • GKSendDataUnreliable — нет гарантии доставки и не гарантируется последовательность данных, но быстро

Примеры

Например, нам нужно подключать всех доступных пиров, обрабатывать их подключение и отключение. Можно сделать так:

- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {

if ( state == GKPeerStateAvailable ) {
// если кто-то доступен - подключаем
[session connectToPeer:peerID withTimeout:10.0];
} else if ( state == GKPeerStateConnected ) {
// обрабатываем подключение пира
} else if ( state == GKPeerStateDisconnected ) {
// обрабатывает отключение пира
}
}

Если в какой-то момент нужно отправить всем данные:

NSData* data = [@"Hello, Devices!" dataUsingEncoding:NSUTF8StringEncoding];

NSError* error = nil;
[session sendDataToAllPeers:data withDataMode:GKSendDataReliable error:&error];

В таком случае всем пирам будет отправлена строка «Hello, Devices!».

Обрабатываем получение данных (при условии что отправили строку):

- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {

NSString* message = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSString* name = [session displayNameForPeer:peer];
// в message - сообщение, которое нам прислали,
// в name - имя того, кто отправил
}

На этом все. Как всегда, доступны исходники. По ссылке находится реализация текстового чата между устройствами. Для проверки вам понадобиться как минимум один девайс и симулятор. Скачать тут.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Добавить комментарий

Ваш адрес email не будет опубликован.