利用 Network.framework 來實做 TCP Socket 連線

Apple 在 iOS 12 後內建了 Socket 連線,讓我們能夠擺脫以往要使用第三方套件來做 Socket 連線的機制,而 Apple 的 Socket 連線是採用了 NWConnection 這個機制,最近海芋剛好要實做 TCP 連線的機制,在使用 ChatGPT 的幫助下,終於寫好了一個簡單的 Socket 連線程式。

swift 1

我是以這個關鍵字去問 ChatGPT。

給我一個完整程式,swift 撰寫socket 連線, 在背景執行序執行, 
需考慮到連線逾時,傳送過程都是使用byte進行傳送接收 ,
在傳送時需考慮到每一筆資料傳送完成後再送下一筆,使用 NWConnection

結果 ChatGPT 馬上生給我範例程式。

class SocketManager {
    private var connection: NWConnection?
    private let queue = DispatchQueue(label: "socketQueue")
    private let host: NWEndpoint.Host
    private let port: NWEndpoint.Port
    
    init(host: String, port: UInt16) {
        self.host = NWEndpoint.Host(host)
        self.port = NWEndpoint.Port(rawValue: port)!
    }
    
    func connect() {
        let parameters = NWParameters.tcp
        connection = NWConnection(host: host, port: port, using: parameters)
        
        connection?.stateUpdateHandler = { [weak self] newState in
            switch newState {
            case .ready:
                print("Connected!")
                self?.receive()
            case .failed(let error):
                print("Connection failed: \(error)")
                self?.connection?.cancel()
            case .cancelled:
                print("Connection cancelled")
            default:
                break
            }
        }
        
        connection?.start(queue: queue)
    }
    
    func send(data: Data) {
        connection?.send(content: data, completion: .contentProcessed({ [weak self] error in
            if let error = error {
                print("Send error: \(error)")
            } else {
                print("Data sent successfully")
            }
        }))
    }
    
    private func receive() {
        connection?.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] (data, context, isComplete, error) in
            if let data = data {
                print("Received data: \(data)")
            }
            
            if isComplete {
                self?.connection?.cancel()
            } else if let error = error {
                print("Receive error: \(error)")
            } else {
                self?.receive()
            }
        }
    }
    
    func disconnect() {
        connection?.cancel()
    }
}

不得不說 ChatGPT 真的很厲害,這樣的確就快寫完了。但是在看了 NWParameters 這個物件後,發現有一些優化可以使用。舉例來說,當我們在解析網站時,會從 DNS Server 要到網站的 ip,而 DNS Server 會有快取的機制,但快取的時間是有限制的,舉例來說可能兩小時就過期了,如果我們在連線時能夠將查詢回來的 DNS 結果先儲存,當連不上時再去問 DNS Server,這樣就可以加速連線的時間,這時我們可以將「expiredDNSBehavior」設為 allow,就可以利用這樣的機制了。

private func getParams() -> NWParameters {
    // 使用 TCP 連線
    let params = NWParameters.tcp
    // 允許使用過期的DNS,若連不上iOS會自動重查並重新連上
    params.expiredDNSBehavior = .allow
    return params
}

另外,如果我們的手機訊號常常在行動網路和wifi間飄移,我們可以採用 Multipath TCP 來做連線,而要開啟這個功能,建議將 multipathServiceType 設為 interactive 或是 aggregate

private func getParams() -> NWParameters {
    // 使用 TCP 連線
    let params = NWParameters.tcp
    // 降低延遲,並同時使用多種網路連線至站台
    params.multipathServiceType = .interactive
    return params
}

以上是略舉兩個簡單的應用,相信你已經想試了,有問題就問 ChatGPT 吧,他會給你很好的靈感的。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments