背景
- 订单支付成功,系统要弹窗提示。
描述
- 用户支付成功的订单,通知到系统
- 通过用户id进行通知,只通知操作订单的用户
- websocket实时通知
目标
- 订单支付成功,系统弹窗提示订单支付成功,避免询问客户是否支付,要求客户出示支付凭证,引起客户反感
需求池
1、 订单支付成功实时通知到系统并弹窗提示。
2、 弹窗在系统页面的右下角
3、 只通知操作所支付订单的人,不通知所有人
研发描述
1.通过websocket实现前后端实时同步。相关技术:websocket、程序逻辑。
2.根据itcode,有针对的通知,谁操作的订单就通知谁。相关技术:程序、数据库表。
3.系统右下角弹窗,实现所有页面都可弹窗提示。相关技术:程序、数据库表。
Web配置文件
<!--websocket监听端口号-->
<add key="port" value="10" />
技术讲解
一、简介
1.服务端
WebSocket是一种在单个TCP连接上进行全双工通信的协议。
WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
WebSocket 是独立的、创建在 TCP 上的协议。
Websocket 通过HTTP/1.1 协议的101状态码进行握手。
为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(handshaking)。
2.客户端
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
以下 API 用于创建 WebSocket 对象。
var Socket = new WebSocket(url, [protocol] );
第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
现在,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。
这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
而比较新的技术去做轮询的效果是Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
二、WebSocket 属性、事件和方法
1.readyState:只读属性 readyState 表示连接状态,可以是以下值:
0 - 表示连接尚未建立。
1 - 表示连接已建立,可以进行通信。
2 - 表示连接正在进行关闭。
3 - 表示连接已经关闭或者连接不能打开。
2.bufferedAmount:只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。
3.事件
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
4.方法
Socket.send() | 使用连接发送数据 |
Socket.close() | 关闭连接 |
三、在C#中使用
1.添加Fleck引用
想要在C#中使用WebSocket,首先得要有个WebSocket支持的C#版的驱动。
通过网络下载或nuget安装,得到Fleck相关的dll,添加到项目中引用。这里介绍下通过NuGet方式添加
第一步:在项目中右键,选择管理NuGet管理包
第二步:搜索Fleck,选择Fleck添加,我这里已经添加过了
通过这两步,会在项目中自动添加Fleck.dll等引用
2.创建websocket类(服务端)
/// <summary>
/// WebSocket帮助类
/// </summary>
public class WebSocketHelp
{
private static Dictionary<IWebSocketConnection, string> allSockets = new Dictionary<IWebSocketConnection, string>();
private static string IPAdderss = IPAddress.Any.ToString();
/// <summary>
/// 开始WebSocket
/// </summary>
/// <param name="port">端口号</param>
public static void Start(int port)
{
FleckLog.Level = LogLevel.Debug;
if (IPAdderss.Equals("0.0.0.0"))
IPAdderss = "127.0.0.1";
WebSocketServer server = new WebSocketServer("ws://" + IPAdderss + ":" + port);
server.Start(socket =>
{
socket.OnOpen = () =>
{
};
socket.OnClose = () =>
{
allSockets.Remove(socket);
};
socket.OnMessage = (name) =>
{
allSockets.Add(socket, name);
};
});
}
/// <summary>
/// 获取信息,发送给客户端
/// </summary>
/// <param name="name">Socket名称(客户端标识)</param>
/// <param name="errMsg">发送的消息</param>
public static void GetMessage(string name, string errMsg)
{
allSockets.Where(s => s.Value == name).ToList().ForEach(s => s.Key.Send(errMsg));
}
}
3.创建websocket(客户端)
<script>
//全局的websocket变量
var ws;
var url = "ws://127.0.0.1:10";
$(function () {
//初始化socket连接
BasisLoad();
});
function BasisLoad() {
//创建连接
console.log("准备连接到" + url);
try {
ws = new WebSocket(url);
console.log(ws);
//连接成功建立后响应
ws.onopen = function () {
console.log("成功连接到" + url);
//发送消息给服务端
ws.send("客户端标识");
}
//收到服务器消息后响应
ws.onmessage = function (e) {
console.log("收到服务器消息:" + e.data + "'\n");
}
//连接关闭后响应
ws.onclose = function (e) {
console.log("关闭连接:");
console.log(e);
ws = null;
}
return false;
} catch (e) {
layer.alert("出错了,浏览器是否支持websocket");
return false;
}
}
</script>