(1)什么是WebSocket
WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。
在WebSocket API中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
优点:
a、服务器与客户端之间交换的标头信息很小,大概只有2字节
b、服务器可以主动传送数据给客户端
(2)WebSocket(13)握手
WebSocket握手由客户端发起,报文样例:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
这里Sec-WebSocket-Version表明版本号是13;注意Sec-WebSocket-Key,这是客户端发送的密钥,服务端需要对该密钥进行处理,反馈给客户端,客户端验证密钥正确后就开始通信,这之后该密钥就没用了。
服务端反馈样例:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
C#服务端首先提取Sec-WebSocket-Key的字符串,加上“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”(是一个固定的GUID),用SHA1计算哈希码,用base64加密,最终生成Sec-WebSocket-Accept的内容。握手代码:
private void handShake(byte[] recBytes, int recByteLength)
{
string recStr = Encoding.UTF8.GetString(recBytes, 0, recByteLength);
string[] ss = recStr.Split(Environment.NewLine.ToCharArray());
string key = ss[10].Replace("Sec-WebSocket-Key: ", "");
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha1 = SHA1.Create();
byte[] sha1bytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(key));
string acceptStr = Convert.ToBase64String(sha1bytes);
string sendStr = "HTTP/1.1 101 Switching Protocols" + NewLine +
"Upgrade: websocket" + NewLine +
"Connection: Upgrade" + NewLine +
"Sec-WebSocket-Accept: " + acceptStr + NewLine +
"Sec-WebSocket-Protocol: chat" + NewLine + NewLine;
client.Send(System.Text.Encoding.UTF8.GetBytes(sendStr));
isHandshaked = true;
}
(3)接收客户端数据
客户端调用send方法将字符窜发送到服务端。服务端要以二进制(bit)解析frame的前两个byte,过程如下:
1byte
1bit: frame-fin,x0表示该message后续还有frame;x1表示是message的最后一个frame
3bit: 分别是frame-rsv1、frame-rsv2和frame-rsv3,通常都是x0
4bit: frame-opcode,x0表示是延续frame;x1表示文本frame;x2表示二进制frame;x3-7保留给非控制frame;x8表示关闭连接;x9表示ping;xA表示pong;xB-F保留给控制frame
2byte
1bit: Mask,1表示该frame包含掩码;0,表示无掩码
7bit、7bit+2byte、7bit+8byte: 7bit取整数值,若在0-125之间,则是负载数据长度;若是126表示,后两个byte取无符号16位整数值,是负载长度;127表示后8个byte,取64位无符号整数值,是负载长度
3-6byte: 这里假定负载长度在0-125之间,并且Mask为1,则这4个byte是掩码
7-end byte: 长度是上面取出的负载长度,包括扩展数据和应用数据两部分,通常没有扩展数据;若Mask为1,则此数据需要解码,解码规则为1-4byte掩码循环和数据byte做异或操作。
C#接收数据代码如下:
private bool recData(byte[] recBytes, int recByteLength)
{
if (recByteLength < 2)
return false;
bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最后一帧
if (!fin)
{
Console.WriteLine("recData exception: 超过一帧"); // 超过一帧暂不处理
return false;
}
bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码
if (!mask_flag)
{
Console.WriteLine("recData exception: 没有Mask"); // 不包含掩码的暂不处理
return false;
}
int payload_len = recBytes[1] & 0x7F; // 数据长度
byte[] masks = new byte[4];
byte[] payload_data;
if (payload_len == 126)
{
Array.Copy(recBytes, 4, masks, 0, 4);
payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]);
payload_data = new byte[payload_len];
Array.Copy(recBytes, 8, payload_data, 0, payload_len);
}
else if (payload_len == 127)
{
Array.Copy(recBytes, 10, masks, 0, 4);
byte[] uInt64Bytes = new byte[8];
for (int i = 0; i < 8; i++)
{
uInt64Bytes[i] = recBytes[9 - i];
}
UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0);
payload_data = new byte[len];
for (UInt64 i = 0; i < len; i++)
payload_data[i] = recBytes[i + 14];
}
else
{
Array.Copy(recBytes, 2, masks, 0, 4);
payload_data = new byte[payload_len];
Array.Copy(recBytes, 6, payload_data, 0, payload_len);
}
for (var i = 0; i < payload_len; i++)
payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]);
string content = Encoding.UTF8.GetString(payload_data);
Console.WriteLine("client: {0}", content);
return true;
}
(3)发送数据到客户端
服务器发送的数据以0x81开头,紧接发送内容的长度(若长度在0-125,则1个byte表示长度;若长度不超过0xFFFF,则后2个byte作为无符号16位整数表示长度;若超过0xFFFF,则后8个byte作为无符号64位整数表示长度),最后是内容的byte数组。
C#发送代码:
private void sendData(string content)
{
byte[] contentBytes = null;
byte[] temp = Encoding.UTF8.GetBytes(content);
if (temp.Length < 126)
{
contentBytes = new byte[temp.Length + 2];
contentBytes[0] = 0x81;
contentBytes[1] = (byte)temp.Length;
Array.Copy(temp, 0, contentBytes, 2, temp.Length);
}
else if (temp.Length < 0xFFFF)
{
contentBytes = new byte[temp.Length + 4];
contentBytes[0] = 0x81;
contentBytes[1] = 126;
contentBytes[2] = (byte)(temp.Length & 0xFF);
contentBytes[3] = (byte)(temp.Length >> 8 & 0xFF);
Array.Copy(temp, 0, contentBytes, 4, temp.Length);
}
else
{
// 暂不处理超长内容
}
client.Send(contentBytes);
}
(4)html客户端代码
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>WebSocket</title>
<script type="text/javascript">
if (!window.WebSocket)
alert("WebSocket not supported by this browser!");
var ws;
function connectWS() {
if (ws == null) {
ws = new WebSocket("ws://127.0.0.1:5001");
ws.onmessage = function (evt) {
alert("接收到信息:" + evt.data);
};
ws.onclose = function () {
alert("连接已关闭。");
ws = null;
};
ws.onerror = function (evt) {
alert("连接出错:" + evt.data);
ws = null;
}
ws.onopen = function (evt) {
alert("连接已打开。");
};
}
}
function sendWS() {
if (ws != null) {
try {
var sendstr = document.getElementById("txtSend").value;
if (sendstr == "")
return;
ws.send(sendstr);
} catch (err) {
alert(err.Data);
}
} else {
alert("连接失效。");
}
}
function closeWS() {
ws.send("exit");
ws.close();
}
</script>
</head>
<body style="text-align: center;">
<input type="button" value="连接" onclick="connectWS()" />
<input type="button" value="断开" onclick="closeWS()" />
<br />
<input type="text" id="txtSend" /><input type="button" id="btnSend" value="发送" onclick="sendWS()" />
</body>
</html>
附件是服务端代码,以及html测试网页
以上
分享到:
相关推荐
C#实现WebSocket源码(c#写的服务端html写的客户端) WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。 它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器...
C# WebSocket 服务端和网页端示例,初学者必备!
C#_WinForm实现WebSocket及时通讯,客户端定向推送。
主要介绍了C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析,包括websocket sharp组件的概念及使用方法,需要的朋友可以参考下
Socket通信含服务端、客户端、WebSocket,代码完整清晰
基于VS2019,使用WinForm作为WebSocket客户端,连接WebSocket服务器并进行数据通信。
IBM Websocket通信c#示例程序
使用Fleck和WebSocketSharp实现WebStock通信,仅为客户端与服务端之间的通信,正在升级为客户端与客户端之间的通信,可以关注我的信息.
WebSocket多线程视频通信
使用c#编写websocket服务端,使用vue编写的客户端,在一台电脑上实现vue发起访问指令,通过websocket协议访问本机websocket服务,服务端接收到指令后开发访问本地资源。不明白的地方加qq286194946
C# 发送websocket通信 需要引用的dll
静态网页通过js与本地C#应用程序基于webSocket实时通讯,调用本地打印机进行post小票打印。服务窗体可最小化托盘,请参考https://blog.csdn.net/weixin_40340362/article/details/89401723
WebSocket是HTML5一种新的协议,它实现了浏览器与服务器全双工通信,这里就将使用WebSocket来开发网页聊天室
websocket Demo实例,直接运行可以进行通信
WebSocketDemo,实现网页与后台的通讯。 WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
所传文档为MFC的SOCKET协议与HTML5里的WEBSOCKET协议之间的通信连接,发送和读写都没有什么问题,另外附带有一个C#的websocket库,库不是开源的,网上也有详细介绍,如果想用C++这块的可以看看,有什么问题可以直接...
完美解决C/S和B/S的通信间问题,可是直接C/S和B/S实时通讯
PC端一般使用c++或c# socket收发信息,网页端只能使用websocket,手机端是java socket。需要将PC端、手机端和网页端,多端打通同时实现即时通讯,就是需要websocket和socket相互通信。
官方.NET库(用C#编写),用于与obs-websocket服务器进行通信。 该库可在有关工作示例,请参见TestClient项目。 什么是新的 v4.9.x逐步添加了obs-websocket v4.9中引入的所有功能 开发人员讨论 Discord:在《 中...