NWConnection - receive() timeout/cancel

How can one implement a connection to a serial terminal server? Sending data to the terminal server is easy but receiving data back from the terminal server is not as the receive command can't be aborted and the NWConnection is considered unusable once a receive has timed out as explained by @eskimo in this thread: https://developer.apple.com/forums/thread/120438.

Any NWConnection use case where the NWEndpoint represents a network media transition point (Ethernet->Serial in case of serial terminal server) must be ready to receive data but the time for receiving is not predictable and not receiving any data for an extended period of time is normal and does not reflect a failure at the NWEndpoint hence should not affect the NWConnection state.

This example becomes even more pertinent when the terminal server connects to a multi drop serial network (e.g. RS485) with multiple devices connected where some of the serial devices may not respond at all (e.g. when powered down). Combined with quick data update times (e.g. 100ms) the problem becomes insurmountable as cancelling the connection (to abort receive) every time a device doesn't respond, will cause lots of unnecessary network traffic.

The only solution I can think of is for NWConnection provide the ability to abort receive() without affecting the NWConnection.

For anyone that thinks "Serial is old, nobody uses it today" - There are tens of thousands of devices in industrial applications which use serial communications and it is essential that modern support software is made available on macOS.

Any suggestions would be much appreciated.

To my mind, as a networking person, you’re approaching this in a very weird way. Compare this sequence:

  1. You send command A to the server.

  2. The server relays command A to a serial device.

  3. The serial device doesn’t respond.

  4. You time out.

  5. You issue command B to the server.

  6. The server relays command B to a serial device.

  7. The serial device responds.

  8. The server relays that to the network.

  9. You receive the response.

With this sequence:

  1. You send command A to server.

  2. The server relays command A to a serial device.

  3. The serial device responds.

  4. The server relays that to the network.

  5. A cosmic ray causes a router between you and the server to reboot.

  6. You time out.

  7. You issue command B to the server.

  8. The router finishes its restart and starts forwarding traffic again.

  9. You finally receive the response to command A.

How do you tell these apart? You need some way to match up requests and responses. If you don’t have that, you just have to guess apply a heuristic.

At the API level, the implementation for this doesn’t involve timeouts or cancelling connections. Rather, you sent up you NWConnection to continuously receive data. You then parse that byte stream into command responses. When you receive a command response, you have to match that up to a pending request.

This is exactly what I was suggesting in my response on that older thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

NWConnection - receive() timeout/cancel
 
 
Q