zeromq / netmq

A 100% native C# implementation of ZeroMQ for .NET
Other
2.96k stars 743 forks source link

Unity3D 2021.3.LTS - Subscriber Crashes @Startup If Publisher Not Sending #1024

Open RMichaelPickering opened 2 years ago

RMichaelPickering commented 2 years ago

Environment

NetMQ Version:    4.0.1.8
Operating System: Windows 10
.NET Version:     .NET Framework (as supported by Unity)

Expected behaviour

On initializing and starting the Subscriber (basic Subscriber pattern) the Subscriber should start successfully and wait for Publisher (a native ZeroMQ C++ app running on same machine) to start and begin sending messages

Actual behaviour

If the Publisher has already been started and is sending messages BEFORE starting Subscriber, everything works as expected, however, if the Subscriber starts before the Publisher is sending messages, the Subscriber crashes with the following error message: SocketException: 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 <1df4a2e55c3e4a6ca5499f3605ed4d9e>:0 at NetMQ.Core.Transports.Tcp.TcpConnector.StartConnecting () [0x00097] in <1df4a2e55c3e4a6ca5499f3605ed4d9e>:0 at NetMQ.Core.Transports.Tcp.TcpConnector.TimerEvent (System.Int32 id) [0x00007] in <1df4a2e55c3e4a6ca5499f3605ed4d9e>:0 at NetMQ.Core.IOObject.TimerEvent (System.Int32 id) [0x00000] in <1df4a2e55c3e4a6ca5499f3605ed4d9e>:0 at NetMQ.Core.Utils.PollerBase.ExecuteTimers () [0x0005f] in <1df4a2e55c3e4a6ca5499f3605ed4d9e>:0 at NetMQ.Core.Utils.Proactor.Loop () [0x0000d] in <1df4a2e55c3e4a6ca5499f3605ed4d9e>:0 at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00014] in :0 at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in :0 at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in :0 at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x0002b] in :0 at System.Threading.ThreadHelper.ThreadStart () [0x00008] in :0 UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object) UnityEngine.DebugLogHandler:LogException(Exception, Object) UnityEngine.Logger:LogException(Exception, Object) UnityEngine.Debug:LogException(Exception) UnityEngine.<>c:b__0_0(Object, UnhandledExceptionEventArgs)

Steps to reproduce the behaviour

Install Unity3D 2021.3.4f1 Install NuGetForUnity (current version is 3.0.5) Using NuGetForUnity, install NetMQ

Write code for the basic Subscriber pattern to run on a background thread, attach to Unity gameobject, build the project Use the standard Publisher code for ZeroMQ on C++, ensure messages are being sent frequently

Run the Subscriber in built Unity app - crashes as above

First run the standard Publisher and ensure messages are being sent - all works fine

RMichaelPickering commented 2 years ago

NOTE: This almost certainly applies to any basic NetMQ Subscriber used in any standard .NET app on Windows. In any case when NetMQ subscriber starts before publisher, the app will crash. The ZeroMQ documentation indicates that running the subscriber before the publisher should work, and I've confirmed this using the Python implementation.

igorbasko01 commented 2 years ago

Hey @RMichaelPickering , Did you find a workaround? I encounter exactly the same issue. The following code is the Unity subscriber:

public class NetMQController : MonoBehaviour
{
    public string topic = "test_topic";
    public string host = "127.0.0.1";
    public int port = 5555;
    private SubscriberSocket _socket;

    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("starting...");
        _socket = new SubscriberSocket();
        _socket.Connect($"tcp://{host}:{port}");
        _socket.Subscribe(topic);
    }

    // Update is called once per frame
    void Update()
    {
        _socket.TryReceiveFrameBytes(out var messageTopic);
        _socket.TryReceiveFrameBytes(out var messageData);
        if (messageTopic != null)
        {
            var shortMessage = messageData != null ? messageData.Take(20) : null;
            Debug.Log($"Got Message from topic: {messageTopic}. Data: {shortMessage}");
        }
    }

    private void OnDestroy()
    {
        _socket.Close();
        NetMQConfig.Cleanup();
    }
}

When I run this subscriber without any publisher online, it throws the same exception as you mentioned. It also crashes if the publisher is stopped before the subscriber.

NetMQ: 4.0.1.10
Unity 2021.3.12f1
Windows 11
igorbasko01 commented 2 years ago

Ok I found something that works, adding AsyncIO.ForceDotNet.Force(); in the Start method, allows running the subscriber before the publisher. Also it is able to reconnect when the publisher goes offline and online again.

void Start()
    {
        AsyncIO.ForceDotNet.Force();
        Debug.Log("starting...");
        _socket = new SubscriberSocket();
        _socket.Connect($"tcp://{host}:{port}");
        _socket.Subscribe(topic);
    }
RMichaelPickering commented 2 years ago

Greetings everyone!

I haven’t noticed this continuing to be an issue, but the workaround that I’ve been using is to NOT start the Subscriber until after the Publisher has started. Please note that I’ve applied a few Unity updates and those may have helped, too.

Regards,

Mike

R. Michael Pickering CBIP President & CEO CloudConstable Incorporated 10271 Yonge Street, Suite 321 Richmond Hill, ON L4C 3B5 Canada www.cloudconstable.comhttp://www.cloudconstable.com/ @.**@.> Toronto: 416-721-1826 Orlando: 321-337-2824 @. @. @.***

From: igorbasko01 @.> Sent: November 13, 2022 2:33 AM To: zeromq/netmq @.> Cc: michael.pickering @.>; Mention @.> Subject: Re: [zeromq/netmq] Unity3D 2021.3.LTS - Subscriber Crashes @Startup If Publisher Not Sending (Issue #1024)

Ok I found something that works, adding AsyncIO.ForceDotNet.Force(); in the Start method, allows running the subscriber before the publisher. Also it is able to reconnect when the publisher goes offline and online again.

void Start()

{

    AsyncIO.ForceDotNet.Force();

    Debug.Log("starting...");

    _socket = new SubscriberSocket();

    _socket.Connect($"tcp://{host}:{port}");

    _socket.Subscribe(topic);

}

— Reply to this email directly, view it on GitHubhttps://github.com/zeromq/netmq/issues/1024#issuecomment-1312659999, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AEABETNJRKA3XJFOOYDQFV3WICKRTANCNFSM526ISOFQ. You are receiving this because you were mentioned.Message ID: @.**@.>>