2011-07-28 18 views
0

私は今ここで問題を抱えているのは百万人に過ぎないと思います。私は誰かが私を確実に助けてくれることを願っています!WebSocketドラフト76ハンドシェイクの混乱

とにかく;私はWebSocketでうまく機能するようにしようとしているこのC#サーバを持っていますが、悲しいことに接続を確立するのに苦労することはありません!私の髪を引き裂くことはどちらも助けにはならない。

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

@ダリンディミトロフ**感謝の気持ちです!@#ER ** <3 –

答えて

0

数字として0または9は含まれていないようです。第2に、_get_key_valuebyte[8]であり、byte[4]ではありません。だから、

、最初(>=<=に注意してください)_get_key_value内部で次のように変更します。それは、常に全体の数になりますので、intにキャストを注意してください(

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

そして、その同じ関数内、以下を変更し、

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

the specための状態:

01の整数で正しい4バイト)を有します

... the | Sec- WebSocket-Key1 |フィールドは、ビッグエンディアンとして表現される32ビット番号、| Sec-WebSocket-Key2 |フィールドは、再び

は、今私は article at Wikipediaの例要求からの正しい応答を取得することができるよ...ビッグエンディアン 32ビット数、と表現しました。

+0

あなたがBig-Endian形式を暗示していること、それをビッグエンディアンに正しく変換していないこと –

+0

私の結果はあなたが言った通りですが、少なくともwiki-pediaの結果と比較しても、これらの変更ではまだ動作しません。しかし、私はまだ接続を確立できません。 レスポンスを送信する前に、\ r \ nまたは\ nを最後に追加する必要がありますか?以前はソケットで作業していたときにはいつもエンディングが必要でした\ 0または\ 0 –

+0

@Kyle Gibbar:ビッグエンディアンを使用していましたが、除算は整数(4バイト)ではなく8バイトになりました。あなたはすべてゼロだった最初の4バイトをコピーしていました。整数にキャストすることで、この問題は解決されました。私はヘッダーとヘッダーとの間の '\ r \ n \ r \ n'の間の終わりを認識していません。 – pimvdb