2011-07-28 50 views
0

我想我可能是百萬分之一的人在這裏有問題;我希望有人可以幫我解決!WebSocket草案76握手混淆

反正;我有這個C#服務器,我試圖用WebSockets良好運行,可悲的是我無法得到該死的東西建立連接!把我的頭髮也沒有幫助。

internal class Request 
    { 
     private delegate void _create_request(Request request); 

     private Request(_create_request create_function) 
     { 
      Headers = new Dictionary<string, string>(); 
      Headers["Upgrade"] = null; 
      Headers["Connection"] = null; 
      Headers["Host"] = null; 
      Headers["Origin"] = null; 
      Headers["Sec-WebSocket-Key1"] = null; 
      Headers["Sec-WebSocket-Key2"] = null; 
      Headers["Sec-WebSocket-Protocol"] = null; 
      Success = false; 
      Secure = false; 
      Method = "GET"; 
      Code = new byte[8]; 

      create_function(this); 
     } 

     /// <summary> 
     /// the code value is the last 8 bytes of the packet 
     /// </summary> 
     public byte[] Code { get; internal set; } 

     /// <summary> 
     /// the resource is the directory being associated with optional extension 
     /// eg: ws://localhost:90/[resource] 
     /// </summary> 
     public string Resource { get; internal set; } 

     /// <summary> 
     /// the resource is the directory being associated with optional extensions 
     /// </summary> 
     public bool Success { get; internal set; } 

     /// <summary> 
     /// this value can either be "GET" 
     /// </summary> 
     public string Method { get; internal set; } 

     /// <summary> 
     /// is this connection using a wss:// or ws:// configuration 
     /// </summary> 
     public bool Secure { get; internal set; } 

     /// <summary> 
     /// these values contain information about our connection 
     /// </summary> 
     public Dictionary<string, string> Headers { get; internal set; } 

     /// <summary> 
     /// this value will give you the responce buffer to pass to the WebSocket server 
     /// </summary> 
     public byte[] Response 
     { 
      get 
      { 
       if (!Success) 
       { 
        return null; 
       } 

       byte[] key_value1 = _get_key_value(Headers["Sec-WebSocket-Key1"]); 
       byte[] key_value2 = _get_key_value(Headers["Sec-WebSocket-Key2"]); 
       byte[] concatenatedKeys = new byte[16]; 

       Array.Copy(key_value1, 0, concatenatedKeys, 0, 4); 
       Array.Copy(key_value2, 0, concatenatedKeys, 4, 4); 
       Array.Copy(Code, 0, concatenatedKeys, 8, 8); 

       // MD5 Hash 
       System.Security.Cryptography.MD5 MD5Service = System.Security.Cryptography.MD5.Create(); 
       byte[] challenge_buffer = MD5Service.ComputeHash(concatenatedKeys); 

       string response = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"; 
       response += "Upgrade: WebSocket\r\n"; 
       response += "Connection: Upgrade\r\n"; 
       response += "Sec-WebSocket-Origin: " + Headers["Origin"] + "\r\n"; 

       string location = ((Secure) ? "wss://" : "ws://") + Headers["Host"] + "/" + Resource; 
       response += "Sec-WebSocket-Location: " + location + "\r\n"; 

       string protocol = Headers["Sec-WebSocket-Protocol"]; 
       if (Headers["Sec-WebSocket-Protocol"] == null) 
       { 
        protocol = "*"; 
       } 
       response += "Sec-WebSocket-Protocol: " + protocol.Trim(' ') + "\r\n"; 
       response += "\r\n"; 

       byte[] response_buffer = new byte[response.Length + 16]; 
       Array.Copy(Encoding.ASCII.GetBytes(response), 0, response_buffer, 0, response.Length); 
       Array.Copy(challenge_buffer, 0, response_buffer, response.Length, 16); 

       return response_buffer; 
      } 
     } 

     internal byte[] _get_key_value(string key) 
     { 
      byte[] value = new byte[4]; 
      ulong r = 0; 
      ulong s = 0; 
      for (int i = 0; i < key.Length; ++i) 
      { 
       if (key[i] > '0' && key[i] < '9') 
       { 
        r = r * 10 + key[i] - '0'; 
       } 
       else if (key[i] == ' ') 
       { 
        s++; 
       } 
      } 
      value = BitConverter.GetBytes(r/s); 
      if (BitConverter.IsLittleEndian) 
      { 
       Array.Reverse(value); 
      } 
      return value; 
     } 

     /// <summary> 
     /// this function will instantiate a new request object, from request data 
     /// </summary> 
     /// <param name="data">the request data</param> 
     /// <returns></returns> 
     internal static Request Instantiate(byte[] data) 
     { 
      string sdata = Encoding.ASCII.GetString(data); 
      return new Request(delegate(Request request) 
      { 
       string _regex_descriptor = @"^([^ ]+)\s\/([^ ]+)\sHTTP/1.1"; 
       string _regex_header = @"\n([^:]+):\s([^\r\n]+)"; 

       string _regex_secure = "^ws([^:]+)?:\\/\\/"; 
       Match match_descriptor = Regex.Match(sdata, _regex_descriptor); 
       MatchCollection match_headers = Regex.Matches(sdata, _regex_header); 

       if (match_descriptor.Success) 
       { 
        request.Method = match_descriptor.Groups[1].Value; 
        request.Resource = match_descriptor.Groups[2].Value; 
        //Console.WriteLine("Method = " + request.Method); 
        //Console.WriteLine("Resource = " + request.Resource); 
       } 
       else return; 
       if (match_headers.Count > 0) 
       { 
        foreach (Match match in match_headers) 
        { 
         if (match.Success) 
         { 
          if (match.Groups[1].Value == "Host") 
          { 
           Match match_secure = Regex.Match(match.Groups[2].Value, _regex_secure); 
           if (match_secure.Success) 
           { 
            request.Secure = (match_secure.Groups[1].Value == "s"); 
           } 
          } 
          request.Headers[match.Groups[1].Value] = match.Groups[2].Value; 
          //Console.WriteLine("Header[\"" + match.Groups[1].Value + "\"] = " + match.Groups[2].Value); 
         } 
        } 
       } 
       else return; 

       Array.Copy(data, data.Length - 8, request.Code, 0, 8); 

       request.Success = true; 
      }); 
     } 
    } 

基本上,如果調用myRequest = Request.Instantiate(byte[] handshake_packet); 然後調用myRequest.Response以生成響應緩衝器;如果有人在我的方法中看到任何問題,請告訴我。因爲在我解決這個問題之前,我真的無法安睡。

+0

試試這個:http://stackoverflow.com/questions/5835944/c-html5-websocket-server/5866975#5866975 –

+0

@Darin Dimitrov **謝謝你MOTHA F!@#ER ** <3 –

回答

0

看起來你不包括09作爲一個數字。其次,_get_key_value返回byte[8]而不是byte[4]

因此,首先更改下列內部_get_key_value(注意:>=<=):

if (key[i] >= '0' && key[i] <= '9') 

和更改相同的功能裏面以下(注意投地int,因爲它永遠是一個整數,並的整數具有4個字節,其是正確的):

value = BitConverter.GetBytes((int)(r/s)); 

由於the spec狀態:

... the | Sec- WebSocket-Key1 |字段,表示爲大字節32位數字,從處理| Sec-WebSocket-Key2 |字段中,再次表示爲大端32位的數字,...

現在我能夠得到從article at Wikipedia的例子請求的正確響應。

+0

什麼是你是在暗示Big-Endian格式,我沒有把它轉換成big-endian? –

+0

儘管我的結果與您所說的一樣,但仍然無法處理這些更改,至少與wiki-pedia結果相比是正確的。但是,我仍然無法建立連接。 在發送回覆之前,我是否需要在最後添加\ r \ n或\ n?我之前記得使用套接字時,我總是需要結尾\ n或\ 0 –

+0

@Kyle Gibbar:您使用的是big-endian,但除法結果不是整數(4字節),而是8字節。您正在複製全部爲零的前4個字節。通過將其轉換爲整數,此問題已解決。我不知道標題和正文之間的標題和\ r \ n \ r \ n是否有結尾,只是'\ r \ n'。 – pimvdb