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

以下のコードを試して、それが機能するかどうかを確認できます。完全な応答を読んでいないのではないかと思います。

    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 に答える
0

データをチェックするための空のループがある、つまりwhile (!stream.DataAvailable){}、回避できるのは本当に悪い習慣です。

readメソッドはである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 に答える