4
votes

I have an exception when I try to receive data from more than three websockets. If I try on only one, two or three websockets it works perfectly. I get the exception in this line:

tasks.Add(Send(webSocket, "11"));

The exception message:

Exception: System.Net.WebSockets.WebSocketException (0x80004005): The 'System.Net.WebSockets.InternalClientWebSocket' instance cannot be used for communication because it has been transitioned into the 'Aborted' state. ---> System.OperationCanceledException: The operation was canceled. at System.Threading.CancellationToken.ThrowOperationCanceledException()
at System.Net.WebSockets.WebSocketConnectionStream.d__21.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at System.Net.WebSockets.WebSocketBase.WebSocketOperation.d__19.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Net.WebSockets.WebSocketBase.d__45.MoveNext() at System.Net.WebSockets.WebSocketBase.ThrowIfAborted(Boolean aborted, Exception innerException) at System.Net.WebSockets.WebSocketBase.ThrowIfConvertibleException(String methodName, Exception exception, CancellationToken cancellationToken, Boolean aborted) at System.Net.WebSockets.WebSocketBase.d__45.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

Here's my code:

using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RTLS_GetData_From_WebSockets.App_Code;

namespace RTLS_GetData_From_WebSockets
{
    class Program
    {
        private static object consoleLock = new object();
        private const int sendChunkSize = 256;
        private const int receiveChunkSize = 256;
        private const bool verbose = true;
        private static readonly TimeSpan delay = TimeSpan.FromMilliseconds(30000);

        private static WebSocket client;
        const string host = "ws://localhost:8080";

        static void Main(string[] args)
        {   
            Connect(host).Wait();
        }

        public static async Task Connect(string uri)
        {
            ClientWebSocket webSocket = null;

            try
            {
                webSocket = new ClientWebSocket();
                await webSocket.ConnectAsync(new Uri(uri), CancellationToken.None);

                List<Task> tasks = new List<Task>();
                tasks.Add(Receive(webSocket));

                tasks.Add(Send(webSocket, "9"));
                tasks.Add(Send(webSocket, "10"));
                tasks.Add(Send(webSocket, "11"));

                await Task.WhenAll(tasks);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception: {0}", ex);
            }
            finally
            {
                if (webSocket != null)
                    webSocket.Dispose();
                Console.WriteLine();

                lock (consoleLock)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("WebSocket closed.");
                    Console.ResetColor();
                }
            }
        }

        static UTF8Encoding encoder = new UTF8Encoding();

        private static async Task Send(ClientWebSocket webSocket, string ZoneID)
        {
            byte[] buffer = encoder.GetBytes("{\"method\":\"subscribe\", \"resource\":\"/zones/" + ZoneID + "\"}");

            await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);

            while (webSocket.State == WebSocketState.Open)
            {
                LogStatus(false, buffer, buffer.Length);
                await Task.Delay(delay);
            }
        }

        private static async Task Receive(ClientWebSocket webSocket)
        {
            byte[] buffer = new byte[receiveChunkSize];
            while (webSocket.State == WebSocketState.Open)
            {
                var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                if (result.MessageType == WebSocketMessageType.Close)
                {
                    await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                }
                else
                {
                    LogStatus(true, buffer, result.Count);
                }
            }
        }

        private static void LogStatus(bool receiving, byte[] buffer, int length)
        {
            lock (consoleLock)
            {
                Console.ForegroundColor = receiving ? ConsoleColor.Green : ConsoleColor.Gray;

                if (verbose)
                {
                    string tmp = encoder.GetString(buffer);                   
                    var data = JsonConvert.DeserializeObject<Zones>(tmp);
                    Console.WriteLine(data.body.status); 
                    Console.WriteLine();
                }

                Console.ResetColor();
            }
        }
    }
}


    [DataContract]
    public class Zones
    {
        [DataMember(Name = "body")]
        public ZoneBody body { get; set; }
    }

    public class ZoneBody
    {
        [DataMember(Name = "feed_id")]
        public string feed_id { get; set; }

        [DataMember(Name = "zone_id")]
        public string zone_id { get; set; }

        [DataMember(Name = "status")]
        public string status { get; set; }

        [DataMember(Name = "at")]
        public string at { get; set; }
    }
1
ClientWebSocket doesn't support parallel send, so who knows what happens when you are trying to send multiple messages in parallel to it. And anyway - why? Send them one by one, doing that in parallel doesn't make any sense to me. – Evk
@Evk Thank you for your advice, it helped me out! – Adam

1 Answers

4
votes

This is from MSDN, here is the link.

This operation will not block. The returned Task object will complete after the send request on the ClientWebSocket instance has completed.

Exactly one send and one receive is supported on each ClientWebSocket object in parallel.

Call your Connect method one by one.