Yes. As you have noticed all user interface interactions must be done from the main thread. (The API layer should be better at blocking the thread and sending the call to the main thread for handling, or at least error-ing out with a meaningful error from calls that require calling on the main thread.)
The correct way would be to have your socket code running on a thread, but marshal the API calls (at least those that require it) to the main thread. The problem is in how to get the calls back to the main thread, because your code is not running an event loop on the main thread, the Fusion application is. For Python, this is a bit of a problem, as there's no really good way (that I'm aware of) to do this.
From a C++ application, you could use native platform APIs to post a message to the main loop, and the Fusion main event loop should dispatch the message (for example, on Windows, you could post a custom windows message and the Fusion event loop will dispatch that message back to your code).
We have discussed, but it is not yet available, adding an API to our API that would allow an addin to send itself events on the main thread, to make a multi-threading application more convenient (for Python code, or for C++ code to do it conveniently and in a platform neutral way).
A less attractive ('poor mans') option would be to have your addin spin in a while loop in your run function, calling adsk.doEvents to pump the main event loop. (This might be what you were doing for your option 1.) This would not be a good general solution, and I would expect it to cause problems with Fusion eventually (which may be the problems you mentioned with option 1) because you never allow Fusion to return to the main event loop. Several critical operations/tasks/idle tasks/etc... are performed when the main event loop is returned to, and spinning in a long term doEvents loop bypasses this.
Another option could be to use a JavaScript addin to do this. The JavaScript code will always run on its own thread and the API calls are always marshalled to Fusion's main thread. But the big problem here is the limited access to the operating system (for example, to open a port). But you could access a local server to make rest calls, or connect to your external node process through a web socket.
Kris
Kris Kaplan