WebSocketListener
WebSocketListener copied to clipboard
Never Sees disconnect from client
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
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.
@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
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.
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.