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

Never Sees disconnect from client #55

Open
netvillage opened this issue Jul 29, 2020 · 4 comments
Open

Never Sees disconnect from client #55

netvillage opened this issue Jul 29, 2020 · 4 comments

Comments

@netvillage
Copy link

If I do a javascript ws.close(); from the client, the server never seems to see it.
The earlier version of vtortola 2.2.0.3 seems to work. A .close() on the client, it will trigger a msg = null after the line
String msg = await ws.ReadStringAsync(cancellation).ConfigureAwait(false);
and set the ws.IsConnected to false, taking it to the finally in the try/catch.
The 4.2.9 version just sits there.
I used the simple echoserver code example and it does the same thing. here's my client side code (which I used to test both old and new):

` var noSupportMessage = "Your browser cannot support WebSocket!";
var ws;

        function appendMessage(message) {
            $('body').append(message);
        }

        function connectSocketServer() {
            var support = "MozWebSocket" in window ? 'MozWebSocket' : ("WebSocket" in window ? 'WebSocket' : null);

            if (support == null) {
                appendMessage("* " + noSupportMessage + "<br/>");
                return;
            }

            appendMessage("* Connecting to server ..<br/>");
            // create a new websocket and connect
            ws = new window[support]("ws://192.168.1.207:8080/");

            // when data is comming from the server, this metod is called
            ws.onmessage = function (evt) {
                appendMessage("# " + evt.data + "<br />");
            };

            // when the connection is established, this method is called
            ws.onopen = function () {
                appendMessage('* Connection open<br/>');
                $('#messageInput').attr("disabled", "");
                $('#sendButton').attr("disabled", "");
                $('#connectButton').attr("disabled", "disabled");
                $('#disconnectButton').attr("disabled", "");
            };

            // when the connection is closed, this method is called
            ws.onclose = function () {
                appendMessage('* Connection closed<br/>');
                $('#messageInput').attr("disabled", "disabled");
                $('#sendButton').attr("disabled", "disabled");
                $('#connectButton').attr("disabled", "");
                $('#disconnectButton').attr("disabled", "disabled");
            }
            ws.onerror = function (event) {
                console.log(event);
                // Sadly, for security reasons you can't get good information on the error
                // If you see "ERR_CERT_DATE_INVALID" from developers console, the server's SSL cert has expired
            }
        }

        function sendMessage() {
            if (ws) {
                var messageBox = document.getElementById('messageInput');
                //ws.send(messageBox.value);
                ws.send(messageBox.value+"\r");
                messageBox.value = "";
            }
        }

        function disconnectWebSocket() {
            if (ws) {
                ws.close();
            }
        }

        function connectWebSocket() {
            connectSocketServer();
        }

        window.onload = function () {
            $('#messageInput').attr("disabled", "disabled");
            $('#sendButton').attr("disabled", "disabled");
            $('#disconnectButton').attr("disabled", "disabled");
        }
<p>To test just an echo back from the server</p>
<input type="button" id="connectButton" value="Connect" onclick="connectWebSocket()" /> 
<input type="button" id="disconnectButton" value="Disconnect" onclick="disconnectWebSocket()" /> 
<input type="text" id="messageInput"/> <input type="button" id="sendButton" value="Send" onclick="sendMessage()" /> 

`

and my C# code here

` public partial class MainWindow : Window {
public IPEndPoint endpoint; // The IP/Port websocket service is listening on
public WebSocketListener server;
CancellationTokenSource cancellation;

    public MainWindow() {
        InitializeComponent();

    }

    private void Window_Loaded(object sender, RoutedEventArgs e) {
        cancellation = new CancellationTokenSource();
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;

        var bufferSize = 1024 * 8; // 8KiB
        var bufferPoolSize = 100 * bufferSize; // 800KiB pool

        var options = new WebSocketListenerOptions
        {
            SubProtocols = new[] { "text" },
            PingTimeout = TimeSpan.FromSeconds(5),
            NegotiationTimeout = TimeSpan.FromSeconds(5),
            PingMode = PingMode.Manual,
            ParallelNegotiations = 16,
            NegotiationQueueCapacity = 256,
            BufferManager = BufferManager.CreateBufferManager(bufferPoolSize, bufferSize)
        };
        options.Standards.RegisterRfc6455(factory =>
        {
            factory.MessageExtensions.RegisterDeflateCompression();
        });
        // configure tcp transport
        
        options.Transports.ConfigureTcp(tcp =>
        {
            tcp.BacklogSize = 100; // max pending connections waiting to be accepted
            tcp.ReceiveBufferSize = bufferSize;
            tcp.SendBufferSize = bufferSize;
        });
        
        IPAddress serverIPAddress;
        serverIPAddress = System.Net.IPAddress.Parse("192.168.1.207");
        endpoint = new IPEndPoint(serverIPAddress, 8080);

        // starting the server
        server = new WebSocketListener(endpoint, options);
        server.StartAsync().Wait();

        Console.WriteLine("Echo Server listening on " + endpoint.ToString());

        Console.WriteLine("You can test echo server at http://www.websocket.org/echo.html.");

        var acceptingTask = AcceptWebSocketsAsync(server, cancellation.Token);

    }

    private static async Task AcceptWebSocketsAsync(WebSocketListener server, CancellationToken cancellation) {
        await Task.Yield();

        while(!cancellation.IsCancellationRequested) {
            try {
                var webSocket = await server.AcceptWebSocketAsync(cancellation).ConfigureAwait(false);
                // This will wait here until we get an incoming connection
                if(webSocket == null) {
                    if(cancellation.IsCancellationRequested || !server.IsStarted)
                        break; // stopped
                    continue; // retry
                }
                EchoAllIncomingMessagesAsync(webSocket, cancellation);
            }
            catch(OperationCanceledException) {
                /* server is stopped */
                break;
            }
            catch(Exception acceptError) {
                Console.WriteLine("An error occurred while accepting client.", acceptError);
            }

        }
        // goes here when: cancellation.Cancel();
        Console.WriteLine("Server has stopped accepting new clients.");
    }

    private static async Task EchoAllIncomingMessagesAsync(WebSocket webSocket, CancellationToken cancellation) {
        Console.WriteLine("Client '" + webSocket.RemoteEndpoint + "' connected.");
        try {
            while(webSocket.IsConnected && !cancellation.IsCancellationRequested) {
                try {
                    var messageText = await webSocket.ReadStringAsync(cancellation).ConfigureAwait(false);
                    if(messageText == null)
                        break; // webSocket is disconnected

                    await webSocket.WriteStringAsync(messageText, cancellation).ConfigureAwait(false);

                    Console.WriteLine("Client '" + webSocket.RemoteEndpoint + "' sent: " + messageText + ".");
                }
                catch(TaskCanceledException) {
                    break;
                }
                catch(Exception readWriteError) {
                    Console.WriteLine("An error occurred while reading/writing echo message.", readWriteError);
                    await webSocket.CloseAsync().ConfigureAwait(false);
                }
            }
        }
        finally {
            webSocket.Dispose();
            Console.WriteLine("Client '" + webSocket.RemoteEndpoint + "' disconnected.");
        }
    }
    private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) {
        Console.WriteLine("Unobserved Exception: ", e.Exception);
    }
    private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
        Console.WriteLine("Unhandled Exception: ", e.ExceptionObject as Exception);
    }
    private void Window_Closed(object sender, EventArgs e) {
        if(server.IsStarted) {
            cancellation.Cancel();
            server.StopAsync().Wait();
            ///acceptingTask.Wait();
        }

    }
}

`

As I mentioned, it's pretty much the echo code, and the older version seems to work

@netvillage
Copy link
Author

well. I think this might be an issue with 4.2.9. because if I change the nuGet package to 4.2.4 and below it seems to be working.

@GusevVasily
Copy link

@deniszykov, +1
I also ran into this problem (v4.2.10). and also the rollback to version 4.2.4 helped to solve the disconnection from the server

@deniszykov
Copy link
Owner

deniszykov commented May 15, 2021

Hi everyone. This one is fixed in 4.2.14

Also don't forget to call webSocket.CloseAsync() after you are done with WebSocket and want to dispose it. I see in your example you close socket only on errors. Current examples from repository contains valid close routine.

@GusevVasily
Copy link

GusevVasily commented May 15, 2021

Hi everyone. This one is fixed in 4.2.14

Also don't forget to call webSocket.CloseAsync() after you are done with WebSocket and want to dispose it. I see in your example you close socket only on errors. Current examples from repository contains valid close routine.

Super! Updated to 4.2.14 and everything worked, thank you.
Just yesterday, nuget did not have this version.

I think the issue can be closed.

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

3 participants