2013-02-08 104 views
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)); 
      } 
     } 
    } 
} 

我錯過了什麼?

回答

2

客戶端和服務器之間的消息不作爲純文本發送。有關如何對它們進行編碼/解碼,請參閱標準的data framing部分。

對於您的客戶端發送一個3字節串的例子,這將導致

  • 1個字節的消息 - 0×81 - 說這是一個非支離破碎的短信
  • 1個字節 - 0x83 - 表示消息正文長度爲3個字節,其內容被屏蔽(所有客戶端 - >服務器消息使用掩碼,服務器 - >客戶端消息不能被屏蔽)。如果消息被屏蔽,則置位最高位(byte_val & 0x80)。剩餘的7位(byte_val & 0x7F)給出了長達125個字節的消息。有關如何確定較長消息的長度,請參閱下面的鏈接。
  • 4字節 - 掩碼。總是4個字節。內容由客戶端確定,並應對每個消息進行更改
  • 3個字節 - 消息。可以使用規範的section 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] 
} 

代碼如果您需要更詳細揭露的消息,this previous post解釋消息發送/接收,並提供了一些實用的僞代碼。

+0

我找到了算法,但我不知道如何使用它。你能舉一個例子嗎? – 2013-02-09 13:10:43

+0

我想你是指揭露消息的算法?我已經用這個 – simonc 2013-02-09 13:22:03

+0

的一個小例子更新了我的答案現在很清楚如何在C#中進行XOR,但是如何確定'bytes'中的掩碼和消息的位置? – 2013-02-09 14:34:10

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); 
+0

我用它來等待'client.Available',以便精確指定字節數組的大小可用。如果傳入數據大於1 kB,會在代碼中發生什麼?我認爲你會得到截斷的數據。 – 2013-02-08 21:27:10

+0

數據將不被**截斷,read函數在while循環內,所以只需在下一次迭代中讀取即可。如果您想一次讀取所有數據,請根據需要使用較大的緩衝區大小。底線,空循環是一種浪費,並不是很好的做法。 – iTech 2013-02-08 21:32:26

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 
        } 

    } 
    } 
+0

我試着用固定的字節數組大小(1 kB),並且仍然沒有從服務器端的消息中得到任何消息。 – 2013-02-09 11:27:00

相關問題