somdoron / AsyncIO

Mozilla Public License 2.0
174 stars 58 forks source link

SocketException when creating one of the NetMQ Sockets on Windows with Mono #37

Open timothyparez opened 4 years ago

timothyparez commented 4 years ago

Consider the following code:

var socket = new RequestSocket();
socket.Connect("tcp://localhost:32700")

On Linux this works fine with Mono On Windows this works fine with .NET But on Windows this crashes with Mono

at AsyncIO.Windows.Socket.SetSocketOption

The first response might be: Just use .NET on Windows but I am using NetMQ in the Godot game engine. When you export your "game" it bundles Mono so it always targets and not .NET.

In other words AsyncIO/NetMQ works great in Godot on Linux, not so much on Windows.

Unhandled Exception:
System.Net.Sockets.SocketException (0x80004005): An invalid argument was supplied.

  at AsyncIO.Windows.Socket.SetSocketOption (System.Net.Sockets.SocketOptionLevel optionLevel, System.Net.Sockets.SocketOptionName optionName, System.Int32 optionValue) [0x00018] in <3c72113274de4b3face0e2579126a901>:0
  at AsyncIO.AsyncSocket.set_NoDelay (System.Boolean value) [0x00000] in <3c72113274de4b3face0e2579126a901>:0
  at NetMQ.Core.Transports.Tcp.TcpConnector.OutCompleted (System.Net.Sockets.SocketError socketError, System.Int32 bytesTransferred) [0x00051] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.Transports.Tcp.TcpConnector.StartConnecting () [0x00097] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.Transports.Tcp.TcpConnector.ProcessPlug () [0x0001b] in <21696b85a92a4a0eb8332ff57aebfd69>:0
waiting
  at NetMQ.Core.ZObject.ProcessCommand (NetMQ.Core.Command cmd) [0x0007a] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.IOThread.Ready () [0x00016] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.IOThreadMailbox.RaiseEvent () [0x00008] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.Utils.Proactor.Loop () [0x00050] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00014] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x0002b] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ThreadHelper.ThreadStart () [0x00008] in <e04d3ec971c54d368992eafd86c45930>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.Net.Sockets.SocketException (0x80004005): An invalid argument was supplied.

  at AsyncIO.Windows.Socket.SetSocketOption (System.Net.Sockets.SocketOptionLevel optionLevel, System.Net.Sockets.SocketOptionName optionName, System.Int32 optionValue) [0x00018] in <3c72113274de4b3face0e2579126a901>:0
  at AsyncIO.AsyncSocket.set_NoDelay (System.Boolean value) [0x00000] in <3c72113274de4b3face0e2579126a901>:0
  at NetMQ.Core.Transports.Tcp.TcpConnector.OutCompleted (System.Net.Sockets.SocketError socketError, System.Int32 bytesTransferred) [0x00051] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.Transports.Tcp.TcpConnector.StartConnecting () [0x00097] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.Transports.Tcp.TcpConnector.ProcessPlug () [0x0001b] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.ZObject.ProcessCommand (NetMQ.Core.Command cmd) [0x0007a] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.IOThread.Ready () [0x00016] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.IOThreadMailbox.RaiseEvent () [0x00008] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at NetMQ.Core.Utils.Proactor.Loop () [0x00050] in <21696b85a92a4a0eb8332ff57aebfd69>:0
  at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00014] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x0002b] in <e04d3ec971c54d368992eafd86c45930>:0
  at System.Threading.ThreadHelper.ThreadStart () [0x00008] in <e04d3ec971c54d368992eafd86c45930>:0
KrunoSaho commented 3 years ago

I have a walk around:

AsyncIO.ForceDotNet.Force();

and

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            NetMQConfig.Cleanup(false);
        }

are the solution.

Working example:

using Godot;
using NetMQ;
using NetMQ.Sockets;

namespace RPG
{
    public class Main : Node2D
    {
        private ResponseSocket _server = null!;
        private RequestSocket _client = null!;

        public override void _Ready()
        {
            AsyncIO.ForceDotNet.Force();

            _server = new ResponseSocket("@tcp://localhost:5556");
            _client = new RequestSocket(">tcp://localhost:5556");

            _client.SendFrame("assss");
            GD.Print(_server.ReceiveFrameString());
        }

        public override void _Process(float delta)
        {
        }

        public override void _Input(InputEvent @event)
        {
            if (@event.IsActionPressed("quit"))
            {
                GetTree().Quit();
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            NetMQConfig.Cleanup(false);
        }
    }
}
timothyparez commented 3 years ago

I will try this, thank you @KrunoSaho