Skip to content

Never Sees disconnect from client #55

@netvillage

Description

@netvillage

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions