[背景]
需要定时查询数据显示到前端,刚开始使用想到的是Ajax长轮询(这样子资源消耗太多了),然后百度,谷歌,发现Http 有一种新的请求方式
WebSocket
WebSocket 是什么?
在没有接触WebSocket
之前,听说过 Socket
,那么 WebSocket
和 Socket
到底是什么,他们二者关系有是什么?
WebSocket
与 Socket
的关系--> 其实讨论这个点的的时候,我想到的 Java
和 Javascript
的关系,但是写文章不能靠自认为,于是我搜索了一下二者联系,发现很多博文都没有说明二者的关系,而是都在对比二者
长答案
当我们探讨两件事物的区别和联系时,我们想探讨些什么?
对于我来说,大多数情况是想知道两件事物本身,而并不是想只想了解「区别」本身。那么对这个问题最直接的解决方法应该是去了解Socket和WebSocket的来源和用法
那么它们的区别和联系就不言自明了。
WebSocket和Socket的区别 作者:TheAlchemist
所以, WebSocket
和 Socket
没有可比性 -->划重点
介绍 一下 WebSocket
&& Socket
WebSocket
WebSocket 是为了满足基于 Web 的日益增长的实时通信需求而产生的(一次请求,终身连接-->这里有点问题,大家明白就好,我主要先说的就是比Ajax定时请求 消耗资源少 _)
在传统的 Web 中,要实现实时通信,通用的方式是采用 HTTP 协议不断发送请求(AJAX 定时请求)
但这种方式即浪费带宽(HTTP HEAD 是比较大的),又消耗服务器 CPU 占用(没有信息也要接受请求)
Socket
Socket可以有很多意思,和IT较相关的本意大致是指在端到端的一个连接中,这两个端叫做Socket。
对于IT从业者来说,它往往指的是TCP/IP网络环境中的两个连接端,大多数的API提供者(如操作系统,JDK)往往会提供基于这种概念的接口
所以对于开发者来说也往往是在说一种编程概念。同时,操作系统中进程间通信也有Socket的概念,但这个Socket就不是基于网络传输层的协议了
作者:TheAlchemist
链接:https://www.jianshu.com/p/59b5594ffbb0/
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
WebSocket
和 Socket
最大的一点 ,就在于传输协议的不同
网上就张很神奇的七层协议图
图片来自此博客
Socket是传输控制层协议 -> 这个靠近中间,不注重数据进行,负责数据传输,速度较快,功能较少
WebSocket是应用层协议-> 应用层靠近用户,然后功能多,所以速度较慢,反向代理,负载均衡,这些都是在这个基础进行
关于 WebSocket
和 Socket
这里我就先讲到这里,
下面是代码实际操作
本篇代码思路来自
C#版Websocket实例 作者:雨落忧伤
下面我就献丑了
后端 NetCore 3.1
前端 Html页面
环境 Windows10
测试浏览器 谷歌
借助工具 nssm ,VS2019
/// <summary>
/// Send 发送
/// </summary>
public class SocketSend
{
private delegate int Weekly(WebSocketServer socket, List<IWebSocketConnection> allSockets,
string Markmessage,
int Marknum,
string ConnectsocketnotificationSection = "已连接",
string ConnectsocketCloseSection = "连接已关闭",
string ReturnMesSection = "数据已更新!"
);
private static int Marknum = 0;
private static string Markmessage = "";
public void Run()
{
var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
var configurationRoot = builder.Build();
var ipaddresSection = configurationRoot.GetSection("ipaddres").Value;
var sockettypeSection = configurationRoot.GetSection("sockettype").Value;
var ipportSection = configurationRoot.GetSection("ipport").Value;
var ConnectsocketnotificationSection = configurationRoot.GetSection("Connectsocketnotification").Value;
var ConnectsocketCloseSection = configurationRoot.GetSection("ConnectsocketCloseSection").Value;
var ReturnMesSection = configurationRoot.GetSection("ReturnMes").Value;
FleckLog.Level = LogLevel.Debug;
var allSockets = new List<IWebSocketConnection>();
var server = new WebSocketServer($"{sockettypeSection }://{ipaddresSection}:{ ipportSection}");
try
{
Weekly weekly = new Weekly(SendMes);
weekly.Invoke(server, allSockets, Markmessage, Marknum, ConnectsocketnotificationSection, ConnectsocketCloseSection, ReturnMesSection);
}
catch (Exception ex)
{
Console.WriteLine($"错误: { ex.Message}");
}
var IsExit = Console.ReadLine();
if (!string.IsNullOrEmpty(IsExit))
{
Console.WriteLine("是否关闭程序(Y/N)");
while (true)
{
IsExit = Console.ReadLine();
if (IsExit != "N")
{
return;
}
}
}
}
/// <summary>
/// Seed
/// </summary>
/// <param name="webSocket"></param>
/// <param name="allSockets"></param>
/// <param name="Markmessage"></param>
/// <param name="Marknum"></param>
/// <param name="ConnectsocketnotificationSection"></param>
/// <param name="ConnectsocketCloseSection"></param>
/// <param name="ReturnMesSection"></param>
/// <returns></returns>
private int SendMes(WebSocketServer webSocket, List<IWebSocketConnection> allSockets,
string Markmessage,
int Marknum,
string ConnectsocketnotificationSection = "",
string ConnectsocketCloseSection = "",
string ReturnMesSection = ""
)
{
webSocket.Start(socket =>
{
socket.OnOpen = () =>
{
Console.WriteLine(ConnectsocketnotificationSection);
allSockets.Add(socket);
};
socket.OnClose = () =>
{
Console.WriteLine(ConnectsocketCloseSection);
allSockets.Remove(socket);
};
socket.OnMessage = message =>
{
Markmessage = message;
Console.WriteLine(Markmessage);
//message 然后开启查询
allSockets.ToList().ForEach(s => s.Send($"Echo: {message}"));
};
});
while (true)
{
Thread.Sleep(100);
if (Markmessage == "OK")
{
//对返回值进行分析
Marknum = ReceiveMes();
// Console.WriteLine("接收num" + Marknum);
if (Marknum == 200)
{
allSockets.ToList().ForEach(s => s.Send(string.IsNullOrEmpty(ReturnMesSection.ToString()) ? "data Upload!" : ReturnMesSection.ToString()));
Console.WriteLine($"收到消息=>{Markmessage} 返回前段消息=>{ReturnMesSection.ToString()}");
Markmessage = "";
}
else
{
allSockets.ToList().ForEach(s => s.Send(Marknum.ToString()));
}
}
Console.WriteLine($"监听前端消息=> {Markmessage}");
}
}
/// <summary>
/// 接收消息 返回 200成功, 500 表示失败
/// </summary>
/// <returns></returns>
private int ReceiveMes()
{
try
{
//数据库查询
//查到修改 则跳出循序
var num = 0;
while (true)
{
Thread.Sleep(100); //每0.1秒查询一次
num++;
Console.WriteLine($"执行数据库查询第{num.ToString()}次");
if (num > 12)
{
break; //跳出数据库查询
}
}
//表示查询到了数据,返回
Console.WriteLine($"查询数据成功,正在进行返回数据操作");
return 200;
}
catch (Exception ex)
{
//记录Log
return 500;
}
}
使用nssm把生成的exe创建成服务 Windows服务方式运行控制台程序
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>websocket client</title>
<script type="text/javascript">
var start = function () {
var inc = document.getElementById('incomming');
var wsImpl = window.WebSocket || window.MozWebSocket;
var form = document.getElementById('sendForm');
var input = document.getElementById('sendText');
inc.innerHTML += "connecting to server ..<br/>";
// create a new websocket and connect
window.ws = new wsImpl('ws://192.168.1.107:50000');
// when data is comming from the server, this metod is called
ws.onmessage = function (evt) {
inc.innerHTML += evt.data + '<br/>';
};
// when the connection is established, this method is called
ws.onopen = function () {
inc.innerHTML += '.. connection open<br/>';
};
// when the connection is closed, this method is called
ws.onclose = function () {
inc.innerHTML += '.. connection closed<br/>';
}
form.addEventListener('submit', function (e) {
e.preventDefault();
var val = input.value;
ws.send(val);
input.value = "";
});
}
window.onload = start;
</script>
</head>
<body>
<form id="sendForm">
<input id="sendText" placeholder="Text to send" />
</form>
<pre id="incomming"></pre>
</body>
</html>
这就是将控制台注入成服务,不过我在这样做的时候,有个问题,就是在使用控制台的时候,能打印出了console,但是注入了服务之后,他就不会有黑窗口了
所以,这里你想每一步操作都发送到前端也可以,或者记录log,但是我这里觉得,还是把每一步操作返回前端,出现错误就log记录,好了,本次文章就写在了这里(认真写文章,真的耗时间)
所以觉得帮到你了,或者我引用其他博主的文章,系列您能都能点个赞,没有他们,也不会有我这篇文章 _
有些问题,我可能没有考虑到,有好的优化方案也请能提出,并附上您的Code
Demo地址
Github: https://github.com/whatarey/WebSocket/tree/master
码云: https://gitee.com/Whatarey/WebSocket