我成功地用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));
}
}
}
}
我在哪里错过了什么?
客户端和服务器之间的消息不会以纯文本形式发送。有关如何对其进行编码/解码,请参阅标准的数据帧部分。
对于客户端发送3字节字符串的示例,这将导致消息
- 1字节-0x81-表示这是一条非碎片文本消息
- 1字节-0x83-表示消息正文为3字节长,其内容被屏蔽(所有客户端->服务器消息都使用屏蔽。服务器->客户端消息不得被屏蔽)。如果消息被屏蔽,则设置最高位(byte_val&0x80)。剩下的7位(byte_val&0x7F)给出了高达125字节的消息长度。有关如何确定较长消息的长度,请参阅下面的链接
- 4字节-掩码。总是4个字节。内容由客户端确定,并且应针对每条消息进行更改
- 3字节-消息。可以使用规范第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]
}
如果您需要更多详细信息,上一篇文章将解释消息发送/接收,并包含一些有用的伪代码。
使用空循环来检查数据(即while (!stream.DataAvailable){}
)确实是一种可以避免的糟糕做法。
读取方法是blocking method
,因此它将等待数据可用
int bufferSize = 1024; // change it as you want
byte[] message = new byte[bufferSize];
readLength = stream.Read(message, 0, bufferSize);
您可以尝试下面的代码,看看它是否有效,我怀疑您没有阅读完整的响应。
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
}
}
}