原理:客户端B(Client/Browser)通过websocket向服务端S发起连接,服务端保存这个websocket连接。当浏览器A(Browser)向服务端发起HTTP请求时,服务端S接收HTTP请求并通过websocket向客户端B返回消息。
流程图:
客户端B的代码:用html实现,用于发送websocket请求和接收。
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<title>websocket client</title>
<script type="text/javascript">
//**************zzt****************
var webSocket;
//HTTP处理程序的地址
var handlerUrl = "ws://localhost:8082/api/Values";
function doConnection() {
InitWebSocket();
}
function SendData() {
var input = document.getElementById('sendText');
//初始化WebSocket
InitWebSocket();
//如果WebSocket打开,发送数据
if (webSocket.OPEN && webSocket.readyState == 1) {
if (input.value != "")
webSocket.send(input.value);
}
//如果WebSocket关闭,显示消息
if (webSocket.readyState == 2 || webSocket.readyState == 3) {
alert("WebSocket关闭了,无法发送数据");
}
}
function CloseWebSocket() {
webSocket.close();
webSocket = undefined;
}
function InitWebSocket() {
//如果WebSocket对象未初始化,我们将初始化它
if (webSocket == undefined) {
webSocket = new WebSocket(handlerUrl);
//打开连接处理程序
webSocket.onopen = function () {
alert("WebSocket已连接");
};
//消息数据处理程序
webSocket.onmessage = function (e) {
var label = '<li>' + e.data + '</li>';
$("#receiveText").append(label);
};
//关闭事件处理程序
webSocket.onclose = function () {
alert("WebSocket closed.");
};
//错误事件处理程序
webSocket.onerror = function (e) {
alert(e.message);
};
}
else {
//webSocket.open();没有open方法
}
}
function doDeleteConnection(devid) {
//初始化WebSocket
InitWebSocket();
//如果WebSocket打开,发送数据
if (webSocket.OPEN && webSocket.readyState == 1) {
webSocket.send("DelConnection^" + devid);
}
//如果WebSocket关闭,显示消息
if (webSocket.readyState == 2 || webSocket.readyState == 3) {
//document.getElementById("di_span").innerText = "WebSocket关闭了,无法发送数据";
alert("WebSocket关闭了,无法发送数据");
}
}
//**************zztend*************
</script>
</head>
<body>
<form id="sendForm">
<input id="sendText" placeholder="Text to send" />
<button type="button" onclick="SendData();">发送</button>
<button type="button" onclick="doConnection();">连接</button>
<button type="button" onclick="CloseWebSocket();">关闭</button>
<br />
<ul id="receiveText"></ul>
</form>
</body>
</html>
客户端A的代码:同样用HTML实现,用于发送Http请求。
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<title>http client</title>
<script type="text/javascript">
function SendData() {
var sendtext = $("#sendText").val();
$.ajax({
type: 'GET',
url: 'http://localhost:8082/api/Values?text=' + sendtext,
dataType: "jsonp", //数据格式设置为jsonp
jsonp: "callback", //Jquery生成验证参数的名称
success: function (e) {
}
});
}
</script>
</head>
<body>
<form id="sendForm">
<input id="sendText" placeholder="Text to send" />
<button type="button" onclick="SendData();">发送</button>
</form>
</body>
</html>
服务端S的代码:用Web API实现,用于接收HTTP和Websocket,还有返回Websocket消息。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.WebSockets;
namespace WebSocketServer.Controllers
{
public class ValuesController : ApiController
{
private static Dictionary<string, object> ws = new Dictionary<string, object>();
// GET api/values
public HttpResponseMessage Get()
{
//检查 查询是否是WebSocket请求
if (HttpContext.Current.IsWebSocketRequest)
{
//如果是,我们附加异步处理程序
HttpContext.Current.AcceptWebSocketRequest(ProcessWSMsg);
}
else
{
//否则,认为是HTTP请求
if (ws.Count > 0)
{
var WebSocket = ws["1"];
var Content = HttpContext.Current.Request["text"];
BackWs((WebSocket)WebSocket, Content);
}
}
return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
}
private async Task ProcessWSMsg(AspNetWebSocketContext arg)
{
//获取当前的WebSocket对象
WebSocket webSocket = arg.WebSocket;
if (ws.ContainsKey("1"))
ws["1"] = webSocket;
else
ws.Add("1", webSocket);
/*
* 我们定义一个常数,它将表示接收到的数据的大小。 它是由我们建立的,我们可以设定任何值。 我们知道在这种情况下,发送的数据的大小非常小。
*/
const int maxMessageSize = 1024;
//received bits的缓冲区
var receivedDataBuffer = new ArraySegment<Byte>(new Byte[maxMessageSize]);
var cancellationToken = new CancellationToken();
//检查WebSocket状态
while (webSocket.State == WebSocketState.Open)
{
//读取数据
WebSocketReceiveResult webSocketReceiveResult = await webSocket.ReceiveAsync(receivedDataBuffer, cancellationToken);
//如果输入帧为取消帧,发送close命令
if (webSocketReceiveResult.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, String.Empty, cancellationToken);
}
else
{
byte[] payloadData = receivedDataBuffer.Array.Where(b => b != 0).ToArray();
//因为我们知道这是一个字符串,我们转换它
string receiveString = System.Text.Encoding.UTF8.GetString(payloadData, 0, payloadData.Length);
//将字符串转换为字节数组.
var newString = String.Format("Hello, " + receiveString + " ! Time {0} 消息来自客户端B", DateTime.Now.ToString());
Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(newString);
//发回数据
await webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, cancellationToken);
}
}
}
/// <summary>
/// 返回websocket消息
/// </summary>
/// <param name="webSocket"></param>
/// <param name="Content"></param>
private void BackWs(WebSocket webSocket,string Content)
{
var cancellationToken = new CancellationToken();
Content = String.Format("Hello, " + Content + " ! Time {0} 消息来自客户端A", DateTime.Now.ToString());
//检查WebSocket状态
if (webSocket.State == WebSocketState.Open)
{
//将字符串转换为字节数组.
Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(Content);
//发回数据
webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, cancellationToken);
}
}
}
}
实现效果: