2011-07-28 45 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