2

I'm trying to write a C# TCP server and get my web app connected. This is the tutorial I'm following. Link

I managed to start the server but the message I got from my webapp is encrypted.

C# Snippet

using System;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace Application
{
class MainClass
{
    public static void Main()
    {
        TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 8181);
        server.Start();

        Console.WriteLine("Server has started on 127.0.0.1:8181.{0}Waiting for a connection...", Environment.NewLine);

        TcpClient client = server.AcceptTcpClient();
        Console.WriteLine("A client connected.");

        NetworkStream stream = client.GetStream();
        while (true)
        {
            while (!stream.DataAvailable) ;

            Byte[] bytes = new Byte[client.Available];

            stream.Read(bytes, 0, bytes.Length);

            String data = Encoding.UTF8.GetString(bytes);

            //handshaking
            if (new Regex("^GET").IsMatch(data))
            {
                Byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + Environment.NewLine
                    + "Connection: Upgrade" + Environment.NewLine
                    + "Upgrade: websocket" + Environment.NewLine
                    + "Sec-WebSocket-Accept: " + Convert.ToBase64String(
                        SHA1.Create().ComputeHash(
                            Encoding.UTF8.GetBytes(
                                new Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
                            )
                        )
                    ) + Environment.NewLine
                    + Environment.NewLine);

                stream.Write(response, 0, response.Length);
            }
            else 
            {
                Console.WriteLine(data);
            }
        }
    }
}
}

HTML Snippet

<form>
<input id="textField1" type="text" style="margin: 0 5px; width: 200px; height: 40px;" placeholder="Enter data">
<button id="sendTextField1" type="button" class="btn btn-info">Send</button>
  </form>
  <script type="text/javascript">
    var start = function () {
    var wsImpl = window.WebSocket || window.MozWebSocket;
    window.ws = new wsImpl('ws://127.0.0.1:8181/');

    ws.onmessage = function (evt) {
      console.log(evt.data);
    };
    ws.onopen = function () {
      console.log("Connected");
    };
    ws.onclose = function () {
      console.log("Closed");
    };

    document.getElementById("sendTextField1").onclick = function() {
      sendToSocket(document.getElementById('textField1').value);
    };

    function sendToSocket(value){
      console.log("Sending value to socket " + value + " ");
      ws.send(value);
    };
}
window.onload = start;

This is what I got from my console enter image description here

I have tried to encode the message to another format but no luck at all.

According to this stackoverflow user,

Messages are not sent in raw format, but they have Data Framing.

Is it relevant to the problem I'm having now? Do I need to find a way to deframe the data I got from the app?

Community
  • 1
  • 1
J.Doe
  • 1,097
  • 1
  • 16
  • 34
  • BTW, whoever wrote that article has **no clue** about correct handling of TCP streams; bleugh - a hot loop over `DataAvailable`, trying to parse packets (via `DataAvailable`) rather than logical frames... eugh; really, really bad example code. – Marc Gravell Aug 16 '16 at 09:57
  • for the record, the example you linked to *does* show the masking code ("Decoding algorithm"), but ... there are so many things to hate in there... – Marc Gravell Aug 16 '16 at 09:59
  • `while (true) { while (!stream.DataAvailable); ...` makes me want to cry – Marc Gravell Aug 16 '16 at 09:59
  • haha sir, I have no clue too, it's an official tutorial from Mozilla, thought it might be useful for novice user – J.Doe Aug 16 '16 at 10:04

1 Answers1

3

Well, this isn't a great start:

String data = Encoding.UTF8.GetString(bytes);

The data sent after the handshake isn't UTF8 text. Parts of it are, but there are binary headers, and there's also something (in RFC6455 at least - possibly not if your client is using Hixie-76) called "Client-to-Server Masking", which means that the data is indeed munged (this is, IIRC, largely to avoid problems with proxy servers, and is not intended to be encryption).

There's also the problem of you looping over the handshake, but: you only handshake once.

Basically, the web-sockets protocol is quite nuanced (and: it is badly/incorrectly implemented by some browsers/versions). Unless you have a very good reason*, I strongly recommend using a library instead of trying to write this by hand. Microsoft provides some level of support in the framework, which should help.


*=I've done this, but for our scenario, the key design reason was scalability - we currently have 464515 open web-socket connections, and the MS implementation just wasn't going to cut it. We made our code freely available, if it helps.

Community
  • 1
  • 1
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks for pointing out my mistake on handshaking part, will amend it after I try using the library you provided. – J.Doe Aug 16 '16 at 09:54
  • @J.Doe actually, *because* that library is intended for stupidly high volume scenarios, it favors performance over friendliness; unless you're game for a little challenge, it may be easier to use *just about any other library* :) – Marc Gravell Aug 16 '16 at 09:58
  • @J.Doe actually, it looks like we did put a nice example together: https://github.com/StackExchange/NetGain#websocket-server-example – Marc Gravell Aug 16 '16 at 10:01
  • Hi sir, I tried NetGain and it works greatly. Actually our web app is intended to provide live video streaming and playback functionality which require us to send binary data. Is NetGain designed for such purpose? – J.Doe Aug 16 '16 at 10:08
  • @J.Doe yes, NetGain will allow you to send binary data. I cannot advise on how suitable it is for video streaming, specifically. In particular, the `message` passed to `Send` can be either a `string` or a `byte[]`, however, for your scenario you might want to be using a buffer-pool or similar. The example shown is a "request / response" example, but in real usage you don't need that - there are methods to send data to the client without requiring a request (which is how you got the update that I'd added a comment here!) – Marc Gravell Aug 16 '16 at 10:21
  • thanks for the help sir, will look into the library deeper! it helps! – J.Doe Aug 16 '16 at 10:26