There’s no reason that doing the same thing in Python or C would have any difference here. However, there are a LOT of ways that you might end up doing something slightly different. The default settings for the sockets might not be the same, buffer sizes could easily vary, etc, etc. So I would be inclined to stick to Python, at least for the time being.
It is somewhat interesting that running in a Linux VM changes matters, but a VM and a host system most commonly work using NAT, so the host system is simply carrying packets, and not managing the connection. Do you have the option to try this in the Windows Subsystem for Linux (WSL)? That would be enlightening.
And this note I find particularly curious:
What do you mean by “failed”? You were unable to get the error? If so, this seems to me like a great avenue of exploration. Try to take your failing app and cut pieces out of it. Does it still fail the same way? Great (in a manner of speaking, of course) - keep cutting pieces out. Does it no longer fail? Then the part you removed might be significant.