[CS193P] 第十七堂課摘要及心得筆記

本系列課程即將邁入最後的尾聲,而在這倒數第三堂課中,我們將學習到如何使用Apple的Bonjour來傳遞網路服務,以及透過NSStream來在網路上進行資料傳輸,此外還有iPhone OS 3.0中所新加入的GameKit套件,就讓我們一起來看看吧!
評論
評論

本系列課程即將邁入最後的尾聲,而在這倒數第三堂課中,我們將學習到如何使用 Apple 的 Bonjour 來傳遞網路服務,以及透過 NSStream 來在網路上進行資料傳輸,此外還有 iPhone OS 3.0 中所新加入的 GameKit 套件,就讓我們一起來看看吧!

Bonjour

Bonjour 是 Apple 在 2002 年所推出的一種網路服務搜索的協定,除了 Mac 和 iPhone 有支援以外,許多網路設備,像是支援網路列印的印表機也都使用 Bonjour 協定。

為了能夠讓讀者了解 Bonjour 的概念,我們做一個簡單的舉例:假設我們想傳送要列印的資料給網路上的印表機,首先必須得先設定印表機的 IP 地址以及其使用的 Port 等等資料,我們的電腦才能將資料傳遞過去。然而,透過支援 Bonjour 服務的印表機,我們就不需要自己手動設定這些 IP 地址等資訊,因為當印表機連上網路的同時,便會自動通知網路上其他支援 Bonjour 的設備,並且傳遞相關的設定資料。

很容易搞混的一點是,Bonjour 只有負責網路服務的尋找,並不負責底層的功能實做,這點需要注意。

在 Bonjour 協定下,每一個裝置都會有自己的代號,這個代號最後的 Domain 通常是以.local. 代表本地的網路,像是 iPhone3GS.local.。而裝置所提供的服務,也有不同的表示方式,如下圖所示:

實際的運用上,NSStream 會透過呼叫 delegate 方法來表示他目前的狀態,但要注意的是,讀取跟寫入仍然是同步執行的,也就是必須另外建立執行緒,否則程式就會卡在網路的傳遞上。

而誠如剛剛所提到的,在我們解析完 NSNetService 之後,可以直接呼叫以下方法取得輸入跟輸出的 NSStream:

NSInputStream *inputStream = nil; NSOutputStream *outputStream = nil; [netService getInputStream:&inputStream outputStream:&outputStream];

在取得 NSStream 之後,我們必須先開啟它,才能進行讀取或寫入,而使用完畢之後,也必須關閉,程式碼如下:

// 開啟 [stream setDelegate:self]; [stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; [stream open];  // 關閉 [stream close]; [stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; [stream setDelegate:nil];

這邊可能大家有發現到,有個 NSRunLoop 的物件出現在呼叫方法中,什麼是 Run Loop 呢?在我們啟動 iPhone 應用程式之後,便會一直在 Run Loop 裡面等待事件的發生,像是觸控事件或是硬體開關的切換等等。而為了能夠讓我們傳輸網路資料,我們必須將 NSStream 物件加入到 Run Loop 上才行。

而如前面所提及的,我們可以透過 NSStream 的 delegate 方法來確定狀況,如下:

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent

而對於已經開啟過的 NSOutputStream 我們就可以呼叫 - (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)length 來進行資料的傳遞,該方法會回傳成功傳送出的資料長度,如下列範例:

const char *buff	= “Hello World!”; NSUInteger buffLen = strlen(buff); NSInteger writtenLength = [outputStream write:(const uint8_t *)buff maxLength:strlen(buff)]; if (writtenLength != buffLen) {     [NSException raise:@”WriteFailure” format:@””]; }

讀取 NSInputStream 的方法也很類似,透過呼叫 - (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)length:

unit8_t buff[1024]; bzero(buff, sizeof(buff)); NSInteger readLength = [inputStream read:buff maxLength:sizeof(buff) - 1]; buff[readLength] = ‘\0’; NSLog(@”Read: %s”, (char *)buff);

GameKit

而在 iPhone OS 3.0 之後便加入了 GameKit 這個 framework,而這個 framework 可以幫助我們透過 Wi-Fi 或是藍牙讓使用者進行配對、建立連線,此外,也有提供音訊聊天的功能。在 GameKit 中提供了以下的類別:

  • GKPeerPickerController -- 呈現使用者配對介面並建立 GKSession
  • GKSession -- 傳遞資訊給單一的使用者或是所有的玩家
  • GKVoiceChatService -- 管理音訊聊天的功能

GKSession 物件是整個 GameKit 的操作核心,我們可以用下列方法建立 GKSession 物件:

- (id)initWithSessionID:(NSString *)sessionID displayName:(NSString *)name sessionMode:(GKSessionMode)mode

而 GKSession 物件則包含了以下屬性:

  • displayName -- 玩家的顯示名稱
  • peerID -- 玩家的 ID,每台 iPhone 均不會重複
  • sessionID -- 你的程式 ID,用來避免不同的應用程式會互相干擾

然而,單純建立好 GKSession 並沒有幫我們完成使用者之間的配對,必須另外透過 GKPeerPickerController,GKPeerPickerController 而提供了兩種方法讓使用者配對,分別是"nearby" 和"online",前者透過藍牙進行配對,iPhone OS 會玩成大部份的工作,後者則是要讓開發者自行建立網路主機,讓使用者可以線上與全球使用者進行配對。

而使用上就如同其他 PickerController 一樣,設定好 delegate 並將 view 加入到畫面上後,物件就會接手處理,並且透過 delegate 方法建立 GKSession:

// 基本設定 GKPeerPickerController *peerPicker; peerPicker = [[GKPeerPickerController alloc] init]; peerPicker.delegate = self;  // 選擇連線模式 peerPicker.connectionMask = GKPeerPickerConnectionTypeOnline | GKPeerPickerConnectionTypeNearby;  // 顯示 alert [peerPicker show];

而當我們取得建立、配對完成的 GKSession 後,就可以簡單的透過以下方法傳送、讀取資料了:

// 傳送資料給特定對象 - (BOOL)sendData:(NSData *)data toPeers:(NSArray *)peers withDataMode:(GKSendDataMode)mode error:(NSError **)error; // 傳送資料給全部人 - (BOOL)sendDataToAllPeers:(NSData *)data withDataMode: (GKSendDataMode)mode error:(NSError **)error; // delegate 方法,接收資料 - (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context;

若有不清楚的地方,可以參考課堂影片中的範例教學,裡面有詳細的操作示範以及範例程式。

結論

這一次的課程中,我們學到如何讓使用者之間能夠進行網路連線的互動,並且使用 GameKit 來簡化整個操作流程。在下一次的課程中,我們將看到如何在 iPhone 上進行 Unit Testing 以及如何建立多國語系支援的應用程式,敬請期待!

參考資源


精選熱門好工作

Brand Management

樂購蝦皮股份有限公司
臺北市.台灣

獎勵 NT$15,000

Backend 工程師

Omlet Arcade 美商歐姆雷特
臺北市.台灣

獎勵 NT$15,000

高階 SRE 專家 / Sr. SRE

奔騰網路科技有限公司
臺北市.台灣

獎勵 NT$15,000

評論