I've just started working on an app that communicates with another device via tcp and I have some doubt.
1) Sometimes the device(server) and the users phone are connected to the same local network and sometimes they are not, when they are I need to use it's local address and when they aren't it's public. How do I handle those transitions ?(eg: when the user walks out of the wireless range)
Is that what the requiredLocalEndpoint is for? I couldn't make it out from the documentation.
2) How to use the betterPathUpdateHandler? I'm pretty sure the server does not support multipath tcp but I need constant communication with it, how do I handle changes between cellular and wireless connection?
My code so far is the following
class CrestronNetwork {
let endpoint = NWEndpoint.hostPort(host: “example.com", port: 11200)
let localEndpoint = NWEndpoint.hostPort(host: "192.168.20.15”, port: 11200)
let parameters = NWParameters.tcp
var connection: NWConnection!
let myQueue = DispatchQueue(label: "Network Queue")
var delegate: NetworkDelegate?
init() {
parameters.multipathServiceType = .disabled
parameters.expiredDNSBehavior = .allow
parameters.requiredLocalEndpoint = localEndpoint
connection = create(endpoint)
}
func create(_ myEndpoint:NWEndpoint) -> NWConnection {
let newConnection:NWConnection
newConnection = NWConnection(to: endpoint, using: parameters)
newConnection.stateUpdateHandler = {
(newState) in switch (newState) {
case .ready:
self.debug("ready")
self.connection = newConnection
self.sendMsg(message: "0-1")
self.receive(on: newConnection)
self.lookForBetterPath(on: newConnection
case .waiting(let error):
self.debugPrint(“Waiting error: \(error)")
case .failed(let error):
self.debugPrint(“Failed: \(error)")
self.start()
case .cancelled:
self.debugPrint(“Cancelled")
default:
break
}
}
newConnection.start(queue: self.myQueue)
return newConnection
}
func lookForBetterPath(on con:NWConnection) {
con.betterPathUpdateHandler = { (betterPathAvailable) in
if (betterPathAvailable) {
self.debugPrint("Better path available")
_ = self.start
}
}
}
func start() {
_ = create(endpoint)
}
func isReady() -> Bool {
if(connection.state == .ready) {
return true
}
return false
}
func sendMsg(message: String) {
let msg = message + "\r\n"
let data: Data? = msg.data(using: .utf8)
connection.send(content: data, completion: .contentProcessed { (sendError) in
if let sendError = sendError {
self.debugPrint(“\(sendError)")
}
})
}
func receive(on con: NWConnection) {
con.receive(minimumIncompleteLength: 1, maximumLength: 8192) { (content, context, isComplete, error) in
if let content = content {
DispatchQueue.main.async {
self.tellViewController(message: String(decoding: content, as: UTF8.self))
}
}
if con.state == .ready && isComplete == false {
self.receive(on: con)
}
}
}
func cancel() {
connection.cancel()
}
func tellViewController(message: String) {
DispatchQueue.main.async {
self.delegate?.passData(data: message)
}
}
}