iOS Swift - 基於TCP和UDP Socket通訊

前言
去年年底“Amazon、Apple、Google、ZigBee Alliance”計畫開發Project Connected Home Over IP(圖一)(圖二)為消費者提升相容性,透過這樣的方式就能夠運用IP通訊協議整合物聯網以及網際網路。而IP(Internet Protocol)為TCP/IP體系中的網路層協議,IP層會將數據包發送至TCP或UDP層,而UDP協議與TCP協議是IP協議與上層協議的介面,透過UDP與TCP協議則能對數據包進行處理。


(圖一)Project Connected Home Over IP

 

(圖二)Project Connected Home Over IP


本文內容主要針對介紹TCP與UDP,以及如何透過Socket API處理IP層的資料來達到傳遞資料的功能,並且提供iOS Swift TCP與UDP App開發的教學範例。

1. 淺談TCP、UDP

TCP(Transmission Control Protocol)UDP(User Datagram Protocol)位於OSI模型與DoD模型(TCP/IP模型)中的傳輸層(圖三),而傳輸層主要負責資料傳輸以及控制,提供可靠或不可靠的遞送方式。

(圖三) 網路參考模型的層級對應


TCP(傳輸控制協議)在資料傳輸方面為可靠的面向連接通信協議,能確保資料傳輸正確和安全。

UDP(用戶數據報協議)在資料傳輸方面則為一個無連接的傳輸協議

TCP與UDP的比較

TCP

UDP

雙向傳輸

(面向連接)

單向傳輸

(面向非連接)

1.     傳輸可靠

2.     保證數據正確性

3.     保證數據順序正確

4.     會重傳遺失資料

5.     提供回傳機制

1.     傳輸不可靠

2.     不能保證數據正確

3.     數據不按順序

4.     不會重傳遺失的資料

5.     不提供回傳機制

用於傳輸大量數據

(流模式)

用於傳輸少量數據

(數據包模式)

速度慢

速度快


2. Socket編程

Socket對TCP/IP或UDP來說是一個抽象的接口,為通信的基石,透過Socket API才能夠使用TCP/IP的協議,使應用層可以和傳輸層透過Socket API執行兩個不同應用程式之間的網路通訊連接,其中包含五種資訊:通訊協議、本地協議位置、本地主機埠、遠端主機埠以及遠端協議埠


3. 
CocoaAsyncSocket介紹及CocoaPods安裝教學

CocoaAsyncSocket程式庫中提供了GCDAsyncSocket類別的使用,其中包含了GCDAsyncSocket類(TCP/IP協議的socket網路庫)以及GCDAsyncUdpSocket類(UDP/IP協議的socket網路庫)

首先,需要透過終端機(Terminal)執行安裝CocoaPods:

輸入完後即可將CocoaPods包(gem)安裝至電腦中(圖四):

(圖四)透過終端機(Terminal)安裝CocoaPods包(gem)至電腦中

成功安裝後,即可在Xcode專案中應用CocoaPods。

接下來透過終端機尋找檔案,新增一個Xcode專案於桌面,且命名為TcpUdpTest,此時在終端機中必須輸入以下指令:

尋找檔案位置(圖五):


初始化pod(圖五):


(圖五)輸入尋找檔案位置以及初始化pod指令

當輸入“pod init”後,在檔案中會生成名叫“Podfile”的檔案(圖六):

(圖六)檔案夾中生成Podfile檔案

接下來開啟Podfile,輸入pod ‘CocoaAsyncSocket’後儲存(圖七),關閉後在終端機輸入“pod install”即可完成(圖八):

(圖七)在Podfile中輸入 pod ‘CocoaAsyncSocket’後儲存檔案

 

(圖八)儲存檔案後,在終端機輸入“pod install”即可安裝CocoaAsyncSocket至檔案中

 

安裝完成後,必須開啟“.xcworkspace”檔(圖九),非“.xcodeproj”檔,之後在編譯程式碼時必須在“.xcworkspace”檔內執行。

(圖九)在“.xcworkspace”檔中編譯程式碼

 

4. iOS APP範例實作(TCP/ UDP)

TCP: 

(圖十)TCP UI範例

(圖十)為TCP UI範例,提供使用者輸入IP地址、輸入Port、綁定端口以及發送訊息,下方對話欄則能出現雙方傳輸的資料以及清空對話欄的功能。

TCP程式碼教學

打開“.xcworkspace”文件後,在ViewController檔案內匯入CocoaAsyncSocket框架

接下來先將“GCDAsyncSocketDelegate”代理設置於ViewController,再定義“socket”變數以及元件連接(圖十一):

 (圖十一)與UIStoryBoard上的元件連接

連接完後,在viewDidLoad()裡即可建立TCP Socket(圖十二):

(圖十二) 建立TCP Socket

接著設置Bind按鈕,這邊將按鈕的動作名稱取名為“connectBtn”,而Bind按鈕名稱為“bindBtn”。

裡面的功能包含「設定按鈕選擇與取消選擇」的功能、「點擊選擇按鈕時則進行連線,點擊取消選擇時則中止連線」的功能以及「區分顏色」的功能(圖十三):

(圖十三) Bind按鈕Action程式碼

Bind按鈕設定完後,接下來設置連線功能(圖十四):

首先,按下Bind按鈕後,按鈕的名稱會顯示為Unbind,再透過“socket.connect(toHost: host, onPort: UInt16, withTimeOut: TimeInterval)”的功能綁定Server IP地址以及端口即可進行連線。

(圖十四)連線功能

當進行連線時,Bind按鈕上的文字為“Unbind”,所以停止連線(圖十五)就必須將按鈕文字再改為“Bind”。再透過“socket.disconnect()”的功能斷開連線。

(圖十五)停止連線

完成設定連線功能與中止連線功能後,即可設定發送按鈕(圖十六)。將訊息輸入框內的文字轉為data格式,再利用“socket.write(Data: data, withTimeOut: TimeInterval, tag: Int)”將資料寫入即可發送,並且顯示訊息在TextView上。

清除按鈕可以清除TextView上的資料,而TextView可以顯示資料傳輸的訊息(圖十六)。


(圖十六)發送按鈕、清除按鈕以及顯示訊息

接下來介紹回調訊息(圖十七),連接成功後透過“didConnectToHost”的功能判斷是否成功連線,若成功連線即可在TextView上顯示連接成功的訊息以及Server IP。而“didRead”的功能是用來接收Server端回傳的訊息,須先將data轉為String格式,再透過“socket.readData”的功能讀取資料,其中dateString()是時間的功能(圖十八);sokectDidDisconnect()則是在斷線時會在TextView上顯示“斷開連接”。

(圖十七)回調訊息

 

(圖十八)時間字串功能


UDP
程式碼教學:

(圖十九)UDP UI 範例


(圖十九)為UDP UI範例,提供使用者輸入Port、綁定端口、發送訊息,下方對話欄則能出現透過廣播讀取同個區網下的訊息資料以及清空對話欄的功能。

UDP程式碼教學:

一開始的作法與TCP類似,首先打開“.xcworkspace”文件後,在UdpViewController檔案內匯入CocoaAsyncSocket框架


接下來先將“GCDAsyncUdpSocketDelegate”代理設置於UdpViewController,再定義“udpSocket”變數以及元件連接(圖二十):

(圖二十)與UIStoryBoard上的元件連接

連接完後,在viewDidLoad()裡即可建立UDP Socket(圖二十一):

(圖二十一)建立UDP Socket

建立完UDP Socket後,接下來設定Bind按鈕(圖二十二),這部分只需綁定端口,成功綁定後會在TextView上顯示時間、已經綁定端口;反之若失敗,就會顯示端口綁定失敗。再透過“.enableBroadcast”的功能開啟廣播以及“.beginReceiving”的功能開啟接收的功能。

(圖二十二)Bind按鈕

綁定端口的功能完成後,即可設定發送按鈕(圖二十三),將資料輸入在對話訊息欄,資料需要轉為data格式,並且透過“udpSocket.send(Data: data, toHost: String, port: UInt16, withTimeout: TimeInterval, tag: Int)”的方式傳送資料。toHost的部分需要輸入的地址為上方定義的“var IP = “255.255.255.255”廣播地址,主要用於發送廣播封包給其他在同個區網下的設備(注意:手機端的區域網路與設備的區域網路必須是相同的,否則將無法發送/接收資料)

(圖二十三)設定發送按鈕

接下來介紹如何接收回調的訊息,透過“didReceive data”(圖二十四)的功能接收Host端的相關訊息,並且在TextView上顯示Host IP以及Host端傳遞的訊息資料。

(圖二十四)didReceive data功能

其他回調的功能包含以下四個(圖二十五),UDP Socket未連線成功、斷開連接、訊息發送失敗以及訊息發送成功。

(圖二十五)回調的功能


(圖二十六)為在TextView上顯示訊息的功能、清除對話訊息欄的資料以及實現時間字串功能。

(圖二十六)TextView上顯示訊息的功能、清除對話訊息欄的資料以及實現時間字串功能

 

結語

以上介紹TCP、UDP的功能如何在iOS Swift中實現,並且透過與電腦中的網路調試助手即可測試TCP、UDP的功能。詳細的操作功能會利用影片的方式呈現,有興趣的讀者不仿可以點擊影片進行觀看!

 

資料來源

  1. Google公布Project Connected Home over IP計劃,推動智慧家庭技術標準: http://iknow.stpi.narl.org.tw/Post/Read.aspx?PostID=16298
  2. 一篇文章看明白TCP/IP,TCP,UDP,IP,Socket 之間的關係: https://blog.csdn.net/freekiteyu/article/details/72236734
  3. 網路調試助手:https://apps.apple.com/cn/app/网络调试助手/id1166859672?mt=12

相關影片

iOS Swift - 基於TCP和UDP Socket通訊

iOS Swift - 基於TCP和UDP Socket通訊

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

參考來源

評論

Yoyo

Yoyo

2021年1月19日
感謝提問! 最上方udpSocket的部分是宣告“var udpSocket: GCDAsyncUdpSocket!”嗎? TCP的部分為 GCDAsyncSocket,而UDP的部分為GCDAsyncUdpSocket,再麻煩你確認一下!
EricLai

EricLai

2020年10月30日
謝謝你的分享,我照著做了,TCP的部分沒又問題, 但是當我在銅一個project當中想做UDP時,我發現建立UDP Socket的地方 Xcode會報錯 就是"udpSocket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)"這個部分 錯誤訊息是 同樣得寫法在TCP是沒問題的,但UDP這部分我真的不知道錯誤在哪裡,想要問你覺得可能是出了什麼問題