Mat*_*uld 4 c# server-side websocket c#-4.0 server
我已经在 C# Web Socket 服务器上工作了大约 24 小时。
我目前已经弄清楚如何完成握手并初始化连接。
我还想出了如何获取byte[]数据并将其解码为原始字符串。
但现在我被困住了,正在寻求帮助。
我似乎无法弄清楚如何组合正确的数据结构并将其发送回客户端。如果您发送原始数据,您在客户端收到的 WebSocket 会告诉您数据不能被屏蔽(这就是为什么需要对其进行解码)。
所以基本上,我要问的是如何构造响应数据以发送回 WebSocket 客户端?
我一直在使用http://tools.ietf.org/html/rfc6455作为我的研究资源。
请记住,我只是为此使用了常规套接字。
这是我的解码代码:
if (dataBuffer.Length > 0)
{
if (dataBuffer[0] == 129)
{
int msg_length = dataBuffer[1] - 128;
if (msg_length <= 125)
{
// Msg ready to decode.
Log.info("Message Length: " + msg_length);
Byte[] decoded = new Byte[dataBuffer.Length];
Byte[] encoded = new Byte[dataBuffer.Length - 6];
Array.Copy(dataBuffer, 6, encoded, 0, msg_length);
Byte[] key = new Byte[4] { dataBuffer[2], dataBuffer[3], dataBuffer[4], dataBuffer[5] };
for (int i = 0; i < encoded.Length; i++)
{
decoded[i] = (Byte)(encoded[i] ^ key[i % 4]);
}
Log.info("MSG: " + Encoding.UTF8.GetString(decoded));
byte[] return_msg = new byte[decoded.Length + 8];
return_msg[0] = 1;
return_msg[1] = 0;
return_msg[2] = 0;
return_msg[3] = 0;
// OP Code
return_msg[4] = 0x1;
return_msg[5] = 0x0;
return_msg[6] = 0x0;
return_msg[7] = 0x0;
Array.Copy(decoded, 0, return_msg, 8, decoded.Length);
socket.Send(return_msg);
}
else if (msg_length == 126)
{
// Longer Message
msg_length = dataBuffer[2] + dataBuffer[3];
Log.info("Message Length: " + msg_length);
Byte[] key = new Byte[4] { dataBuffer[4], dataBuffer[5], dataBuffer[6], dataBuffer[7] };
Byte[] decoded = new Byte[dataBuffer.Length];
Byte[] encoded = new Byte[dataBuffer.Length - 8];
Array.Copy(dataBuffer, 8, encoded, 0, msg_length);
for (int i = 0; i < encoded.Length; i++)
{
decoded[i] = (Byte)(encoded[i] ^ key[i % 4]);
}
Log.info("MSG: " + Encoding.UTF8.GetString(decoded));
byte[] return_msg = new byte[decoded.Length + 4];
return_msg[0] = 129;
return_msg[1] = 0;
return_msg[2] = 0;
return_msg[3] = 0;
Array.Copy(decoded,0,return_msg,4,decoded.Length);
socket.Send(return_msg);
}
else if (msg_length == 127)
{
// Huge Message:
Log.info("BIG MESSAGE");
}
}
}
Run Code Online (Sandbox Code Playgroud)
@vtortola 感谢您发布链接和解释 - 我花了很多时间研究它和一个开源代码库(基本上是我自己写的),然后我将其提炼成这个,以便从服务器向客户端发送消息。
对我来说,关键是意识到几件事:
首先,了解标题。GetHeader() 负责它是否是最后一帧以及操作码是否设置为连续帧的文本。@vtortola 发布的链接对此进行了解释,但在看到这些内容之前,我必须真正盯着它:
这篇文章实际上很好地解释了它,但你必须花时间研究它——注意 FIN 和操作码位如何匹配 GetHeader() 的工作:
接下来,了解您在调用 stream.Write() - bytes[], index, LENGTH OF BYTES You're SENDING 时发送的内容;)
注意:我的意图是将 JSON 格式的字符串发送到 Web 客户端和从 Web 客户端发送,因此我的操作码是为文本设置的(这里的示例基于您想要发送字符串数据的假设),但您可以发送其他类型以及。
SendMessageToClient()基本上将消息分成 125 个块并创建一个要从中提取的队列。根据我们在队列中的位置,使用适当的 FIN 和操作码标志创建标头。最后,准备好标题后,用字符串块的实际长度(<= 125)回填标题的其余部分。然后在将其转换为字节数组后将标头写入流。
此时,您的标头已正确创建(FIN、rsv1、2、3 设置正确,操作码和掩码以及有效负载的大小)。现在发送。
public void SendMessageToClient(TcpClient client, string msg)
{
NetworkStream stream = client.GetStream();
Queue<string> que = new Queue<string>(msg.SplitInGroups(125));
int len = que.Count;
while (que.Count > 0)
{
var header = GetHeader(
que.Count > 1 ? false : true,
que.Count == len ? false : true
);
byte[] list = Encoding.UTF8.GetBytes(que.Dequeue());
header = (header << 7) + list.Length;
stream.Write(IntToByteArray((ushort)header), 0, 2);
stream.Write(list, 0, list.Length);
}
}
protected int GetHeader(bool finalFrame, bool contFrame)
{
int header = finalFrame ? 1 : 0;//fin: 0 = more frames, 1 = final frame
header = (header << 1) + 0;//rsv1
header = (header << 1) + 0;//rsv2
header = (header << 1) + 0;//rsv3
header = (header << 4) + (contFrame ? 0 : 1);//opcode : 0 = continuation frame, 1 = text
header = (header << 1) + 0;//mask: server -> client = no mask
return header;
}
protected byte[] IntToByteArray(ushort value)
{
var ary = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(ary);
}
return ary;
}
/// ================= [ extension class ]==============>
public static class XLExtensions
{
public static IEnumerable<string> SplitInGroups(this string original, int size)
{
var p = 0;
var l = original.Length;
while (l - p > size)
{
yield return original.Substring(p, size);
p += size;
}
yield return original.Substring(p);
}
}
Run Code Online (Sandbox Code Playgroud)
除了上面的帖子,我还研究了websocket-sharp 的代码库。我真的想学习如何做到这一点,写我自己的服务器/客户端,并能做到学习代码库以及作为一个伟大的起点,在这里创建一个基本的C#的WebSocket服务器。
最后,我感谢上帝耐心阅读所有这些内容;)
| 归档时间: |
|
| 查看次数: |
11427 次 |
| 最近记录: |