Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.ObjectDisposedException while sending payload. #331

Closed
larryr1 opened this issue Jul 29, 2023 · 1 comment
Closed

System.ObjectDisposedException while sending payload. #331

larryr1 opened this issue Jul 29, 2023 · 1 comment

Comments

@larryr1
Copy link

larryr1 commented Jul 29, 2023

This is a really weird one...
I'm trying to send thumbnails of my desktop to a server over the socket connection. The process goes like so:

  • The JS server requests a thumbnail be sent, with acknowledgement.
  • my C# client's event system routes the event to a handler depending on the event that was sent.
  • The thumbnail is downscaled to 1/4 of whatever the desktop resolution is and the BMP data is converted to a UTF-8 string.
  • The string is returned to my event handler code where it is sent in the acknowledgement.

When calling response.CallbackAsync(reply.StringData) I get a System.ObjectDisposedExcetion. Stack trace:

String data has length of 518344
Sending reply.
Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
Handler threw System.ObjectDisposedException: The semaphore has been disposed.
   at System.Threading.SemaphoreSlim.CheckDispose()
   at System.Threading.SemaphoreSlim.Release(Int32 releaseCount)
   at SocketIOClient.Transport.WebSockets.WebSocketTransport.<SendAsync>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at SocketIOClient.Transport.BaseTransport.<SendAsync>d__29.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at SocketIOClient.SocketIO.<ClientAckAsync>d__107.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at SocketIOClient.SocketIOResponse.<CallbackAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Rustera.Classes.EventManager.EventManager.<socketEvent>d__10.MoveNext() in C:\Users\larry\source\repos\Rustera\Rustera\Classes\EventManager\EventManager.cs:line 143

Here is the code that is responsible for routing the event and responding to the callback. I have omitted several try/catch and if statements for brevity.

#pragma warning disable IDE1006 // Naming Styles
private static async void socketEvent(string eventName, SocketIOResponse response)
#pragma warning restore IDE1006 // Naming Styles

{
    Debug.WriteLine("Got event. " + eventName);

    // The SocketIOResponse class is really confusing and undocumented. I had to look at it's source to figure out
    // what it's method and properties were.
    // I'm only doing it this way because I can't synchronously access arguments in the same event if I use the documented way
    // in the repository's README. Below is the reference for the class.
    // https://github.com/doghappy/socket.io-client-csharp/blob/5a7b8e331908edcd722eca955d249d1f0e8656aa/src/SocketIOClient/SocketIOResponse.cs#L9

    // The response has each argument sent from the server in a list.
    // You can access each element of this list by calling response.getValue() with it's index.
    // I ignore all other elements because the server should be sending arguments in a JSON object as the first event arugment.
    string potentialJson = response.GetValue(0).ToString();

    // Create the object
    JObject json;
    json = JObject.Parse(potentialJson);

    // Args for handler
    SocketEventArgs eventArgs = new SocketEventArgs
    {
        EventName = eventName,
        Argument = json
    };

    // Get handler for this event
    ISocketEventHandler handler = eventHandlers.Find(h => h.EventName == eventName);

    // Execute handler
    try
    {
        SocketEventReply reply = handler.HandleEvent(eventArgs);
        Debug.WriteLine("String data has length of " + reply.StringData.Length);
        if (reply.StringData != null)
        {
            Debug.WriteLine("Sending reply.");
            await response.CallbackAsync(reply.StringData);
        }

    } catch (Exception ex)
    {
        Debug.WriteLine("Handler threw " + ex.ToString());
    }
}

This is the code that sets up the event handler.

public static void Initialize()
{
    socketManager = new SocketManager();
    OnAnyHandler handler = new OnAnyHandler(socketEventThreadRunner);
    socketManager.GetClient().OnAny(handler);
    socketManager.GetClient().ConnectAsync().Wait();
}

private static void Io_OnConnected(object sender, EventArgs e)
{
    Console.WriteLine("IO Connected to server");
}

private static void socketEventThreadRunner(string eventName, SocketIOResponse response)
{
    Thread thread = new Thread(() => { socketEvent(eventName, response); });
    thread.Start();
}

private static async void socketEvent(string eventName, SocketIOResponse response) {...}

I am using undocumented classes for some of the methods, but it appears that I am allowed to use them because they are public and they appear in the overloads for things like client.onAny(...).

I'm really lost on what to do next here. Any help is greatly appreciated.

@larryr1
Copy link
Author

larryr1 commented Jul 30, 2023

I've done some more research.
It turns out, Socket.IO has a serverside maximum buffer size to prevent clients trying to overload the server. The amount of data I was sending (~0.5MB) was violating this limit. Adjusting my server's configuration to allow larger packet sizes fixed the problem.

@larryr1 larryr1 closed this as completed Jul 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant