I figured out why my app hangs: the server issues two TCPCloseSocket() calls. It doesn’t crash the server, but the client needs to be exited. The situation is like closing the door on someone while they’re talking, and you can still hear their voice.
After the last TCPRecv(), the client should send a concluding message. The server waits for this receipt, this confirmatory goodbye, and then calls TCPCloseSocket(). Meanwhile, the client blocks on TCPSend(); returning means the data was sent. Now the client can close. (If the client’s final message isn’t the expected farewell, something went wrong.)
Without the final receipt, the server “slams the door” on the connection, the (first) blind TCPSocketClose(). The client hangs on receiving data and never reaches its own socket-close. Because the socket isn’t explicitly closed, the server “accepts” the same connection. This time, since the message isn’t conformant with the protocol (a conditional check), control goes straight to the bottom, the TCPCloseSocket(). That’s the second time.
This was an elusive bug because the app “never” hanged for me until I launched it to a group of users. They were pretty good at getting the app to freeze. It was embarrassing. My first assumption was slow batch scripts. Maybe cmd.exe was slow and RunWait() timed out. I changed the server to use FileOpen() and FileRead() more often without outsourcing to the interpreter. But it still froze.
Next, I set up every task on the server to do only one of two things: send a file or send a variable. Anything that needed processing, like sorting an array, would be done client-side. The app continued to hang, so I did not think it was an issue with disk latency. It had to be the network.
It was only thanks to debug statements that I detected the double socket close. Because the server could still respond to clients while other clients froze, I would likely have never discovered such pathology until I let loose the stepwise ConsoleWrite()’s. Whenever the server closed the socket twice, the corresponding client would hang. Bingo.
If this works in the wild, I’ll pull out the useful parts into a networking library. I don’t know how long I will be using AutoIt or desktop apps, but it’s a useful prototype technique to whip up a single-threaded client-server app for local solutions. Synchronization is a non-issue, because data writes are serialized by connection.
To me, that’s a minor miracle.