Hi everyone,
I'm developing an iOS app using Swift (Foundation, Network, and Combine) that communicates via TCP with a weighing scale. The scale uses an internal ESP32 module acting as a Wi-Fi Access Point (no internet access) specifically for data transmission. The app connects to this network and opens a socket to receive weight data and send command strings.
I’m currently facing two main issues:
Socket Management: The socket isn't closing properly. Occasionally, the app opens multiple simultaneous connections instead of maintaining a single one. Since the ESP32 has a client limit, these ghost connections eventually hang the communication module.
Invalid Outbound Data: The connection drops frequently because the scale receives invalid strings from the app. My logs show strange character sequences (like "gggggggggfdhj" or "vfgdddddddddddtty") being sent involuntarily. I haven't programmed these strings, and they cause the scale to terminate the session due to protocol violations.
How can I ensure proper socket closure and prevent these random data packets?
Additionally, a technical question: Is it possible to keep this TCP connection active in the background indefinitely on iOS while the user interacts with other apps?
You’re using the term socket as a synonym for network connection. That’s not correct, and it muddies the waters when it comes to how to approach this problem. For example, one of your issues relates to connection viability, and the best way to handle that problem varies depending on whether you’re using the BSD Sockets API or the Network framework API.
Is it possible to keep this TCP connection active in the background indefinitely on iOS while the user interacts with other apps?
No. See iOS Background Execution Limits.
Invalid Outbound Data … My logs show strange character sequences (like "gggggggggfdhj" or "vfgdddddddddddtty") being sent involuntarily.
It’s very unlikely that’s being generated by Network framework. The majority of times when I see problems like this it’s because the app itself is sending that junk, usually because it’s using unsafe pointers. However, the Swift code you posted contains no unsafe pointers (yay!) so that’s not the cause.
The next thing to look at is concurrency. Network framework itself is thread safe. That is, you can work with a single NWConnection from multiple threads without the connection itself getting confused. However, it’s best to confine access to the connection to be from a single thread (or queue) just so you avoid confusing yourself.
Looking at your code I see two queues in play:
- You create a custom serial queue (
self.queue) for theNWConnection. - You also do work on the main queue.
This is likely to cause problems. For example, you current manipulate self.buffer from both queues — in disconnect() to work with it from the main queue and in receive() you work with it from the connection’s queue — and that’s undefined behaviour in Swift.
IMO you should just use the main queue for everything here. Using a secondary queue makes sense if your pushing a lot of data through the connection, but that’s clearly not the case here.
If that doesn’t fix things, the next step is to use an RVI packet trace to see what’s happening on the ‘wire’. This will tell you whether the junk is being generated on the send side by the iOS device or on the receive side by your accessory.
Connection Management: The connection isn't closing properly.
It’s hard to offer insight without a lot more details about who is closing the connection and when. One specific thing to watch out for is connection defuncting. TN2277 Networking and Multitasking explains this concept, albeit under an older name (socket resource reclaim). If your app suspends and the connection gets defuncted, the remote peer won’t hear about this unless it tries to send some traffic on the connection. So, it’s important that you not let this happen, usually by closing the connection as your app moves to the background.
If that’s not in then I’m gonna need a more detail explanation as to what triggers this problem.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"