Sándor Rakonczai
Sándor Rakonczai

Reputation: 213

Server does not get the message of client

I successfully made a WebSocket server in C# which I can connect to. I make the handshake as RFC 6455 requires it.

Whatever I send (via WebSocket.send()) to it (for example "asd") the stream only has 9 bytes of data which is "unrepresentable" by UTF8.

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

class Server
{
    public static void Main()
    {
        TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 80);

        server.Start();

        TcpClient client = server.AcceptTcpClient();
        NetworkStream stream = client.GetStream();

        Boolean isHandshaked = false;

        while (true)
        {
            while (!stream.DataAvailable)
            {
            }

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

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

            if (!isHandshaked)
            {
                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(
                                    Encoding.UTF8.GetString(bytes)
                                ).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
                            )
                        )
                    ) + Environment.NewLine
                     + Environment.NewLine);

                stream.Write(response, 0, response.Length);

                isHandshaked = true;
            }
            else
            {
                Console.WriteLine(Encoding.UTF8.GetString(bytes));
            }
        }
    }
}

Where I missed something?

Upvotes: 0

Views: 724

Answers (3)

simonc
simonc

Reputation: 42205

Messages between client and server are not sent as plain text. See the data framing section of the standard for how to encode/decode them.

For your example of a client sending a 3 byte string, this will result in a message of

  • 1 byte - 0x81 - saying that this is a non-fragmented text message
  • 1 byte - 0x83 - saying that the message body is 3 bytes long and it's contents are masked (all client -> server messages use masking. server -> client messages must not be masked). The top bit (byte_val & 0x80) is set if a message is masked. The remaining 7 bits (byte_val & 0x7F) gives the length of the messages up to 125 bytes. See link below for how to determine the length of longer messages.
  • 4 bytes - mask. Always 4 bytes. Content determined by the client and should change for each message
  • 3 bytes - message. Can be decoded using the mask and algorithm in section 5.3 of the spec.

You can unmask a message using code like the following

byte mask[4];
byte[] msg_data;
// read message, initialising mask, msg_data
for (int i=0; i<msg_data.Length; i++)
{
    msg_data[i] = msg_data[i] ^ mask[i%4]
}

If you need more detail, this previous post explains message sending/receiving and includes some helpful pseudo code.

Upvotes: 2

DotNetUser
DotNetUser

Reputation: 6612

You can try code below and see if it works, i suspect you are not reading full response.

    byte[] buffer = new byte[4155];
    int bytesRead = 0;

    using (var input = client.GetStream())
    {
      while (true)
                    {
                        bytesRead = input.Read(buffer, 0, buffer.Length);
                        totalBytes += bytesRead;
                        if (bytesRead > 0)
                            // keep processing ur data here, add it to another buffer maybe
                        else
                            break; // come out of while loop if there is no data
                    }

    }
  }

Upvotes: 0

iTech
iTech

Reputation: 18460

Having an empty loop to check for data i.e. while (!stream.DataAvailable){} is really a bad practice that you can avoid.

The read method is a blocking method, so it will wait until the data is available

int bufferSize = 1024; // change it as you want
byte[] message = new byte[bufferSize];
readLength = stream.Read(message, 0, bufferSize);

Upvotes: 0

Related Questions