我认为我可能是第一百万在这里遇到问题的人;我希望有人可以帮我肯定!
反正;我有这个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 :(得分:0)
您似乎不包含0
或9
作为数字。其次,_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声明:
... | Sec- WebSocket-Key1 |字段,表示为big-endian 32位数,从处理| Sec-WebSocket-Key2 |获得的数字。字段,再次表示为big-endian 32位数,...
现在,我可以从article at Wikipedia的示例请求中获得正确的响应。