Skip to content

Instantly share code, notes, and snippets.

@NVentimiglia
Forked from xamlmonkey/WebSocketWrapper.cs
Last active July 19, 2017 13:20
Show Gist options
  • Select an option

  • Save NVentimiglia/50014880057d26f7743f to your computer and use it in GitHub Desktop.

Select an option

Save NVentimiglia/50014880057d26f7743f to your computer and use it in GitHub Desktop.

Revisions

  1. Nicholas Ventimiglia revised this gist May 11, 2015. 1 changed file with 37 additions and 54 deletions.
    91 changes: 37 additions & 54 deletions WebSocketWrapper.cs
    Original file line number Diff line number Diff line change
    @@ -4,27 +4,27 @@
    using System.Threading;
    using System.Threading.Tasks;

    namespace Coe.WebSocketWrapper
    namespace System.Net.Sockets
    {
    public class WebSocketWrapper
    public class WebSocketWrapper : IDisposable
    {
    private const int ReceiveChunkSize = 1024;
    private const int SendChunkSize = 1024;

    private readonly ClientWebSocket _ws;
    public readonly ClientWebSocket Client;
    private readonly Uri _uri;
    private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
    private readonly CancellationToken _cancellationToken;

    private Action<WebSocketWrapper> _onConnected;
    private Action<string, WebSocketWrapper> _onMessage;
    private Action<WebSocketWrapper> _onDisconnected;
    public event Action<WebSocketWrapper> OnConnected;
    public event Action<WebSocketWrapper, string> OnMessage;
    public event Action<WebSocketWrapper> OnDisconnected;

    protected WebSocketWrapper(string uri)
    protected WebSocketWrapper(Uri uri)
    {
    _ws = new ClientWebSocket();
    _ws.Options.KeepAliveInterval = TimeSpan.FromSeconds(20);
    _uri = new Uri(uri);
    Client = new ClientWebSocket();
    Client.Options.KeepAliveInterval = TimeSpan.FromSeconds(20);
    _uri = uri;
    _cancellationToken = _cancellationTokenSource.Token;
    }

    @@ -33,7 +33,7 @@ protected WebSocketWrapper(string uri)
    /// </summary>
    /// <param name="uri">The URI of the WebSocket server.</param>
    /// <returns></returns>
    public static WebSocketWrapper Create(string uri)
    public static WebSocketWrapper Create(Uri uri)
    {
    return new WebSocketWrapper(uri);
    }
    @@ -49,38 +49,13 @@ public WebSocketWrapper Connect()
    }

    /// <summary>
    /// Set the Action to call when the connection has been established.
    /// </summary>
    /// <param name="onConnect">The Action to call.</param>
    /// <returns></returns>
    public WebSocketWrapper OnConnect(Action<WebSocketWrapper> onConnect)
    {
    _onConnected = onConnect;
    return this;
    }

    /// <summary>
    /// Set the Action to call when the connection has been terminated.
    /// </summary>
    /// <param name="onDisconnect">The Action to call</param>
    /// <returns></returns>
    public WebSocketWrapper OnDisconnect(Action<WebSocketWrapper> onDisconnect)
    {
    _onDisconnected = onDisconnect;
    return this;
    }

    /// <summary>
    /// Set the Action to call when a messages has been received.
    /// Connects to the WebSocket server.
    /// </summary>
    /// <param name="onMessage">The Action to call.</param>
    /// <returns></returns>
    public WebSocketWrapper OnMessage(Action<string, WebSocketWrapper> onMessage)
    public void Disconnect()
    {
    _onMessage = onMessage;
    return this;
    Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Normal", CancellationToken.None);
    }

    /// <summary>
    /// Send a message to the WebSocket server.
    /// </summary>
    @@ -92,15 +67,15 @@ public void SendMessage(string message)

    private async void SendMessageAsync(string message)
    {
    if (_ws.State != WebSocketState.Open)
    if (Client.State != WebSocketState.Open)
    {
    throw new Exception("Connection is not open.");
    }

    var messageBuffer = Encoding.UTF8.GetBytes(message);
    var messagesCount = (int)Math.Ceiling((double)messageBuffer.Length / SendChunkSize);

    for (var i = 0; i < messagesCount; i++)
    for (var i = 0;i < messagesCount;i++)
    {
    var offset = (SendChunkSize * i);
    var count = SendChunkSize;
    @@ -111,13 +86,13 @@ private async void SendMessageAsync(string message)
    count = messageBuffer.Length - offset;
    }

    await _ws.SendAsync(new ArraySegment<byte>(messageBuffer, offset, count), WebSocketMessageType.Text, lastMessage, _cancellationToken);
    await Client.SendAsync(new ArraySegment<byte>(messageBuffer, offset, count), WebSocketMessageType.Text, lastMessage, _cancellationToken);
    }
    }

    private async void ConnectAsync()
    {
    await _ws.ConnectAsync(_uri, _cancellationToken);
    await Client.ConnectAsync(_uri, _cancellationToken);
    CallOnConnected();
    StartListen();
    }
    @@ -128,20 +103,20 @@ private async void StartListen()

    try
    {
    while (_ws.State == WebSocketState.Open)
    while (Client.State == WebSocketState.Open)
    {
    var stringResult = new StringBuilder();


    WebSocketReceiveResult result;
    do
    {
    result = await _ws.ReceiveAsync(new ArraySegment<byte>(buffer), _cancellationToken);
    result = await Client.ReceiveAsync(new ArraySegment<byte>(buffer), _cancellationToken);

    if (result.MessageType == WebSocketMessageType.Close)
    {
    await
    _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
    Client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
    CallOnDisconnected();
    }
    else
    @@ -162,31 +137,39 @@ private async void StartListen()
    }
    finally
    {
    _ws.Dispose();
    Client.Dispose();
    }
    }

    private void CallOnMessage(StringBuilder stringResult)
    {
    if (_onMessage != null)
    RunInTask(() => _onMessage(stringResult.ToString(), this));
    if (OnMessage != null)
    RunInTask(() => OnMessage(this, stringResult.ToString()));
    }

    private void CallOnDisconnected()
    {
    if (_onDisconnected != null)
    RunInTask(() => _onDisconnected(this));
    if (OnDisconnected != null)
    RunInTask(() => OnDisconnected(this));
    }

    private void CallOnConnected()
    {
    if (_onConnected != null)
    RunInTask(() => _onConnected(this));
    if (OnConnected != null)
    RunInTask(() => OnConnected(this));
    }

    private static void RunInTask(Action action)
    {
    Task.Factory.StartNew(action);
    }

    public void Dispose()
    {
    if (Client != null)
    {
    Client.Dispose();
    }
    }
    }
    }
    }
  2. @xamlmonkey xamlmonkey renamed this gist Feb 8, 2013. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. @xamlmonkey xamlmonkey renamed this gist Feb 8, 2013. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. @xamlmonkey xamlmonkey created this gist Feb 8, 2013.
    192 changes: 192 additions & 0 deletions gistfile1.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,192 @@
    using System;
    using System.Net.WebSockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;

    namespace Coe.WebSocketWrapper
    {
    public class WebSocketWrapper
    {
    private const int ReceiveChunkSize = 1024;
    private const int SendChunkSize = 1024;

    private readonly ClientWebSocket _ws;
    private readonly Uri _uri;
    private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
    private readonly CancellationToken _cancellationToken;

    private Action<WebSocketWrapper> _onConnected;
    private Action<string, WebSocketWrapper> _onMessage;
    private Action<WebSocketWrapper> _onDisconnected;

    protected WebSocketWrapper(string uri)
    {
    _ws = new ClientWebSocket();
    _ws.Options.KeepAliveInterval = TimeSpan.FromSeconds(20);
    _uri = new Uri(uri);
    _cancellationToken = _cancellationTokenSource.Token;
    }

    /// <summary>
    /// Creates a new instance.
    /// </summary>
    /// <param name="uri">The URI of the WebSocket server.</param>
    /// <returns></returns>
    public static WebSocketWrapper Create(string uri)
    {
    return new WebSocketWrapper(uri);
    }

    /// <summary>
    /// Connects to the WebSocket server.
    /// </summary>
    /// <returns></returns>
    public WebSocketWrapper Connect()
    {
    ConnectAsync();
    return this;
    }

    /// <summary>
    /// Set the Action to call when the connection has been established.
    /// </summary>
    /// <param name="onConnect">The Action to call.</param>
    /// <returns></returns>
    public WebSocketWrapper OnConnect(Action<WebSocketWrapper> onConnect)
    {
    _onConnected = onConnect;
    return this;
    }

    /// <summary>
    /// Set the Action to call when the connection has been terminated.
    /// </summary>
    /// <param name="onDisconnect">The Action to call</param>
    /// <returns></returns>
    public WebSocketWrapper OnDisconnect(Action<WebSocketWrapper> onDisconnect)
    {
    _onDisconnected = onDisconnect;
    return this;
    }

    /// <summary>
    /// Set the Action to call when a messages has been received.
    /// </summary>
    /// <param name="onMessage">The Action to call.</param>
    /// <returns></returns>
    public WebSocketWrapper OnMessage(Action<string, WebSocketWrapper> onMessage)
    {
    _onMessage = onMessage;
    return this;
    }

    /// <summary>
    /// Send a message to the WebSocket server.
    /// </summary>
    /// <param name="message">The message to send</param>
    public void SendMessage(string message)
    {
    SendMessageAsync(message);
    }

    private async void SendMessageAsync(string message)
    {
    if (_ws.State != WebSocketState.Open)
    {
    throw new Exception("Connection is not open.");
    }

    var messageBuffer = Encoding.UTF8.GetBytes(message);
    var messagesCount = (int)Math.Ceiling((double)messageBuffer.Length / SendChunkSize);

    for (var i = 0; i < messagesCount; i++)
    {
    var offset = (SendChunkSize * i);
    var count = SendChunkSize;
    var lastMessage = ((i + 1) == messagesCount);

    if ((count * (i + 1)) > messageBuffer.Length)
    {
    count = messageBuffer.Length - offset;
    }

    await _ws.SendAsync(new ArraySegment<byte>(messageBuffer, offset, count), WebSocketMessageType.Text, lastMessage, _cancellationToken);
    }
    }

    private async void ConnectAsync()
    {
    await _ws.ConnectAsync(_uri, _cancellationToken);
    CallOnConnected();
    StartListen();
    }

    private async void StartListen()
    {
    var buffer = new byte[ReceiveChunkSize];

    try
    {
    while (_ws.State == WebSocketState.Open)
    {
    var stringResult = new StringBuilder();


    WebSocketReceiveResult result;
    do
    {
    result = await _ws.ReceiveAsync(new ArraySegment<byte>(buffer), _cancellationToken);

    if (result.MessageType == WebSocketMessageType.Close)
    {
    await
    _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
    CallOnDisconnected();
    }
    else
    {
    var str = Encoding.UTF8.GetString(buffer, 0, result.Count);
    stringResult.Append(str);
    }

    } while (!result.EndOfMessage);

    CallOnMessage(stringResult);

    }
    }
    catch (Exception)
    {
    CallOnDisconnected();
    }
    finally
    {
    _ws.Dispose();
    }
    }

    private void CallOnMessage(StringBuilder stringResult)
    {
    if (_onMessage != null)
    RunInTask(() => _onMessage(stringResult.ToString(), this));
    }

    private void CallOnDisconnected()
    {
    if (_onDisconnected != null)
    RunInTask(() => _onDisconnected(this));
    }

    private void CallOnConnected()
    {
    if (_onConnected != null)
    RunInTask(() => _onConnected(this));
    }

    private static void RunInTask(Action action)
    {
    Task.Factory.StartNew(action);
    }
    }
    }