Coder Social home page Coder Social logo

ninja.websockets's Introduction

Ninja WebSockets

A concrete implementation of the .Net Standard 2.0 System.Net.WebSockets.WebSocket abstract class

A WebSocket library that allows you to make WebSocket connections as a client or to respond to WebSocket requests as a server. You can safely pass around a general purpose WebSocket instance throughout your codebase without tying yourself strongly to this library. This is the same WebSocket abstract class used by .net core 2.0 and it allows for asynchronous Websocket communication for improved performance and scalability.

Dependencies

No dependencies.

Getting Started

As a client, use the WebSocketClientFactory

var factory = new WebSocketClientFactory();
WebSocket webSocket = await factory.ConnectAsync(new Uri("wss://example.com"));

As a server, use the WebSocketServerFactory

Stream stream = tcpClient.GetStream();
var factory = new WebSocketServerFactory();
WebSocketHttpContext context = await factory.ReadHttpHeaderFromStreamAsync(stream);

if (context.IsWebSocketRequest)
{
    WebSocket webSocket = await factory.AcceptWebSocketAsync(context);
}

Using the WebSocket class

Client and Server send and receive data the same way.

Receiving Data:

private async Task Receive(WebSocket webSocket)
{
    var buffer = new ArraySegment<byte>(new byte[1024]);
    while (true)
    {
        WebSocketReceiveResult result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
        switch (result.MessageType)
        {
            case WebSocketMessageType.Close:
                return;
            case WebSocketMessageType.Text:
            case WebSocketMessageType.Binary:
                string value = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
                Console.WriteLine(value);
                break;
        }
    }
}

Receive data in an infinite loop until we receive a close frame from the server.

Sending Data:

private async Task Send(WebSocket webSocket)
{
    var array = Encoding.UTF8.GetBytes("Hello World");
    var buffer = new ArraySegment<byte>(array);
    await webSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
} 

Simple client Request / Response: The best approach to communicating using a web socket is to send and receive data on different worker threads as shown below.

public async Task Run()
{
    var factory = new WebSocketClientFactory();
    var uri = new Uri("ws://localhost:27416/chat");
    using (WebSocket webSocket = await factory.ConnectAsync(uri))
    {
        // receive loop
        Task readTask = Receive(webSocket);

        // send a message
        await Send(webSocket);

        // initiate the close handshake
        await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);

        // wait for server to respond with a close frame
        await readTask; 
    }           
}

WebSocket Extensions

Websocket extensions like compression (per message deflate) is currently work in progress.

Running the tests

Tests are written for xUnit

Authors

David Haig

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

Further Reading

This library is based on all the amazing feedback I got after writing this article (thanks all): https://www.codeproject.com/articles/1063910/websocket-server-in-csharp

The code in the article above was written before Microsoft made System.Net.WebSockets.WebSocket generally available with .NetStandard 2.0 but the concepts remain the same. Take a look if you are interested in the inner workings of the websocket protocol.

ninja.websockets's People

Contributors

mallibone avatar ninjasource avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ninja.websockets's Issues

Question about data frame received after close

our product is this, we have a C# application using Ninja.WebSockets to send data to a browser application which is embedded in chrome.

Recently we get couple of errors from chrome side with this error message both from Windows and Mac platforms.
WebSocket connection to 'ws://localhost:49758/' failed: Data frame received after close

I checked that chrome does have a thread about this while they won't fix it.
https://bugs.chromium.org/p/chromium/issues/detail?id=372776

I want to consult check with the experts here as I see that SendAsync in this library does not check whether the WebSocket's State is open or not while other API does this check. If I add this kind of check in SendAsync, will this solve the error (Data frame received after close) we see?

Invalid pointer address in attempting to use a pointer. Possible DNS issue ?

Hello there,
I had a strange issue while trying to connect to my websocket server :

SocketException: The system detected an invalid pointer address in attempting to use a pointer argument in a call.

I tried to narrow down the problem and see exactly where this exception happens but no success with that. It seems related to our DNS setup (could be a wrong config on our side).

Some context: the server is deployed in a Kubernetes node, which has a IP address. We have 3 nodes in total and a master node.
Nginx listens on the 3 nodes and delegates the request to the appropriate service. So we have in total 4 IP addresses in the game (3 minions and 1 master).
By talking with a colleague about my issue, we figured out that a DNS lookup on the hostname of my server returns 3 IP addresses, which should be the 3 minions but it happens to be 2 minions and 1 master. That's where we have it wrong and we will fix that, this should resolve my issue.

But then he told me that all our browser services, that uses websockets libraries don't have this problem. Apparently if they fail, they retry on the next IP.

So my question is this one: is there any retry on fail when trying to establish a connection ? Are you even able to catch this kind of exception in the library or does it happen in the C# source and you cannot do anything about this ?

Unable to connect using wss, works with ws

I tried connected demo client with ws and it works as expected, but when I tried to connect it with wss it is not decrypting the handshake message.
image
Here it is unable to decrypt the wss handshaking message.

How to use this?

I'm having problems figuring out how to use this code...
My biggest issue is that I can't seem to figure out how the DemoServer works. When trying to follow your wiki and build it that way, this is the message I get as soon as I start sending data from the client: WebSocket is already in CLOSING or CLOSED state.
If I use the example I keep getting the blob as a response...
And I can't figure out how to actually show the data received on the server in the console

Documentation of exceptions thrown

Hello, we're big fans of the Ninja WebSockets library and wrote an adapter to expose WebSocket functionality to our users through our library.

One question that has often come up from our users is what types of exceptions they can expect to be surfaced from the library, and in what cases these exceptions fire. For example, looking through the code, there are potential exceptions related to streams, cancelled operations, cancelled tasks (a subset of cancelled operations), and more.

We can test this empirically and we know to some extent it may depend on the platform, but it would be great to get a word from the author on the general design of what exceptions are thrown and when.

Send message to a specific client

Hi, I need to developer a function using a WebSocket and send some messages to some specific clients, how can I request a connected websocket client using your library?

In the url I have a "?clientId=12345", i can see it on header and save in a variable, but I dont have idea how search it on the websocket.

Thank you

SSL support?

Hi,
Is there a way to enable secure websockets with this package? So that we use wss://localhost:portnr?

Need .Net 4.5 support.

Could you please support .Net at least 4.5?
We really want to use this in our project which is target to .Net 4.5 and also run in Xamarin.Mac.

One to many broadcast?

Hello all,

I've been looking at this project and it looks pretty stellar. One thing I am not seeing is a broadcast method, is there a method available to do a one to many broadcast? If not, any pointers or tips to build a method around this lib to achieve this?

Thanks!
L

Unable to specify correct buffer size for ReceiveAsync

In the documents of WebSocket.ReceiveAsync it's no where written that the buffer passed to method needs to be as big as the biggest websocket frame expected to be received. Since the receiver as any way no real influence on the frame size chosen by the sender its impossible to set the size correctly. Further WebSocket.ReceiveAsync was designed that the receiver can use smaller buffers than the messages to be able to for example write the received message parts into a file or other stream not requiring to keep all bytes in memory.

I assume the .net core own implementation splits the frames int chunks because I haven't seen the issue there. How can I receive frames bigger than the buffer with ninja?

Would like to use a custom JSON payload in PingPongManager

I would like to be able to use a custom payload in the PingPongManager. For example, the ping-pong protocol for Slack involves sending the following payload:

{
    "id": 1234,
    "type": "ping",
    "time": 1403299273342
}

and getting back the following:

{
    "reply_to": 1234,
    "type": "pong",
    "time": 1403299273342
}

I believe I need to be able to set the payload that gets sent in the private async Task PingForever() method, but current cannot see how to do that.

EDIT: A bit more investigation of the code reveals that the Slack ping-pong is not the same as the standard websockets ping-pong, in that it is actually a message exchange of the JSON above, so it looks like I am going to have to write it myself, based off of your excellent netstandard 2.0 library :-)

Ninja.WebSockets.dll is no longer signed with a strong name key

I can see that a similar issue was raised previously in #8 which was resolved back in 2018. Looking at the NuGet releases, v1.1.3 was signed with a Strong Name Key (SNK), but the DLL in the subsequent releases is not signed.

Is the intention to provide unsigned libraries through the NuGet release? I would prefer to consume the library as a generic package instead of incorporating it directly into my project solution, but my project must be signed.

ILSpy Data:
v1.0.1.3
// Ninja.WebSockets, Version=1.0.1.3, Culture=neutral, PublicKeyToken=e9d9b92674c8641a
// Global type:
// Architecture: AnyCPU (64-bit preferred)
// Runtime: v4.0.30319
// This assembly is signed with a strong name key.
// Hash algorithm: SHA1
// Public key: 0024000004800000940000000602000000240000525341310004000001000100b1707056f4761b7846ed503642fcde97fc350c939f78026211304a56ba51e094c9cefde77fadce5b83c0a621c17f032c37c520b6d9ab2da8291a21472175d9caad55bf67bab4bffb46a96f864ea441cf695edc854296e02a44062245a4e09ccd9a77ef6146ecf941ce1d9da078add54bc2d4008decdac2fa2b388e17794ee6a6

v1.0.1.7
// Ninja.WebSockets, Version=1.0.1.7, Culture=neutral, PublicKeyToken=null
// Global type:
// Architecture: AnyCPU (64-bit preferred)
// Runtime: v4.0.30319
// Hash algorithm: SHA1

Websocket ID?

When receiving a message from a client as a server, is there any identifier that would tell me which websocket sent the message?

One or more errors occurred. (502 Bad Gateway) while connecting to Azure

Hi, I'm experiencing a 502 error while I'm connecting my ninja ws client to a ws server deployed on Azure.
The error could be easily reproduced by using the "Ninja.WebSockets.DemoClient" and try to connect to the following endpoint:
ws://websocketforpyqt.azurewebsites.net

  1. Please note that I also tried different ws clients (written in python, javascript, net full framework, net core) and everything worked fine.
  2. The web socket server deployed on the azure endpoint is the one you can find on this github repo. It's written in c# using asp.net 3.1 core framework.
  3. If it can help, I can tell you that at the moment I found a (bad) work around: I deployed the ws server on a VM which has a public static IP address. In that way ninja client is able to connect and consume successfully the ws server.

So my conclusion is: seems ninja is not able to resolve the Azure DNS name properly, because seems the cloud normally doesn't work with public ips.
Really appreciate the time you takes to read my post.

Bye
Ennio

Custom PingPong implementation (server)

Hi,
I'm developing a websocket server based on Ninja.WebSockets nuget but I cannot find out how to properly manage the pong message.
There is a client that periodically sends me (the server) a ping request, but, even if I set the KeepAliveInterval option, it does not receive any proper reply. I found the PingPongManager class, but it only offers the Pong event and the SendPing() method... I need the opposite: a Ping event and a SendPong() method.
Is there a way to solve this issue?

Digging a little deeper in your code, I found that a method in WebSocketImplementation class:
private async Task SendPongAsync(ArraySegment<byte> payload, CancellationToken cancellationToken)

Would it be possible to have it as public?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.