0

我成功地用 C# 制作了一个可以连接的 WebSocket 服务器。我按照 RFC 6455 的要求进行握手。

无论我(通过WebSocket.send())向它发送什么(例如“asd”),流都只有 9 个字节的数据,这些数据是 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));
            }
        }
    }
}

我错过了什么?

4

3 回答 3

2

客户端和服务器之间的消息不是以纯文本形式发送的。有关如何对它们进行编码/解码,请参阅标准的数据帧部分。

对于您发送 3 字节字符串的客户端示例,这将导致消息

  • 1 字节 - 0x81 - 表示这是一条非分段短信
  • 1 字节 - 0x83 - 表示消息体长 3 个字节并且其内容被屏蔽(所有客户端 -> 服务器消息都使用屏蔽。服务器 -> 客户端消息不得被屏蔽)。如果消息被屏蔽,则设置最高位 (byte_val & 0x80)。剩余的 7 位 (byte_val & 0x7F) 使消息的长度最多为 125 个字节。有关如何确定较长消息的长度,请参阅下面的链接。
  • 4 个字节 - 掩码。始终为 4 个字节。由客户端确定的内容,应针对每条消息进行更改
  • 3 个字节 - 消息。可以使用规范第 5.3 节中的掩码和算法进行解码。

您可以使用如下代码取消屏蔽消息

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]
}

如果您需要更多详细信息,前一篇文章解释了消息发送/接收,并包含一些有用的伪代码。

于 2013-02-09T12:13:38.270 回答
0

有一个空循环来检查数据 iewhile (!stream.DataAvailable){}确实是您可以避免的不好的做法。

read 方法是 a blocking method,所以它会等到数据可用

int bufferSize = 1024; // change it as you want
byte[] message = new byte[bufferSize];
readLength = stream.Read(message, 0, bufferSize);
于 2013-02-08T20:49:03.453 回答
0

您可以尝试下面的代码,看看它是否有效,我怀疑您没有阅读完整的回复。

    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
                    }

    }
  }
于 2013-02-08T21:49:47.863 回答