[C#]使用WebSocket進行廣播功能 - 透過WebSocketSharp
WebSocket 是 HTML5 開始提供的一種瀏覽器與伺服器間進行全雙工通訊的網路技術,通訊協定被 IETF 定為標準 RFC 6455
Client與Server之間只需要做過一次handshark兩端邊建立起一條TCP的通道,兩者之間就能進行資料的傳輸
自己動手實作 RFC 6455其實是累人的一件事情, 在Go專案上如果要自己造輪子實為非常累人,
建議還是要花點時間了解RFC6455
今天要介紹的是使用C#實作一個廣播中心 - 透過WebSocketSharp這一個套件
目錄結構如下
Server 端程式
1. MessageQueueSingleton.cs為單例模式的一個佇列存取類別, 提供廣播訊息的存入與取出
using System;
using System.Collections.Concurrent;
namespace WS.Demo.Controller {
public class MessageQueueSingleton {
private static volatile MessageQueueSingleton _instance;
private static object _lockObj = new object();
private static ConcurrentQueue<string> _msgQueue;
private MessageQueueSingleton() { }
public static MessageQueueSingleton Instance() {
if (_instance == null) {
lock (_lockObj) {
if (_instance == null) {
_instance = new MessageQueueSingleton();
_msgQueue = new ConcurrentQueue<string>();
}
}
}
return _instance;
}
public void AddMsg() {
try {
_msgQueue.Enqueue(DateTime.Now.ToString("yyyyMMddHHmmssfff"));
} catch (Exception ex) {
//do something
}
}
public void GetMsg(out string msg) {
msg = null;
try {
lock (_lockObj) {
if (!_msgQueue.TryDequeue(out msg)) {
msg = null;
}
}
} catch (Exception ex) {
//do something
}
}
public void FreeQueue() {
lock (_lockObj) {
string temp;
while (_msgQueue.TryDequeue(out temp)) {
}
}
}
}
}
2. BroadcastBehavior.cs WebSocket Server 針對廣播功能的行為定義類別
using System.Text;
using System.Threading;
using WebSocketSharp.Server;
namespace WS.Demo.Controller {
public class BroadcastBehavior : WebSocketBehavior {
/// <summary>
/// 建構子
/// </summary>
public BroadcastBehavior() { }
/// <summary>
/// WebSocket會話建立後調用Fn
/// </summary>
protected override void OnOpen() {
/***
* 一直從MessageQueueSingleton取出字串,正確取得就進行廣播
***/
while (true) {
string msg = null;
MessageQueueSingleton.Instance().GetMsg(out msg);
if (msg != null) {
Sessions.BroadcastAsync(Encoding.UTF8.GetBytes(msg), null);
}
Thread.Sleep(1);
}
}
}
}
3. Program.cs 程式進入點
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using WS.Demo.Controller;
using WebSocketSharp.Server;
namespace WS.Demo {
class Program {
static void Main(string[] args) {
//每250秒加入一個廣播訊息至MessageQueue
var msgCreater = new Thread(() => {
while (true) {
MessageQueueSingleton.Instance().AddMsg();
Thread.Sleep(250);
}
});
msgCreater.Start();
//WebSocketServer 監聽 PORT 55688
var wssv = new WebSocketServer(55688);
wssv.AddWebSocketService<BroadcastBehavior>("/Broadcast");
wssv.Start();
if (wssv.IsListening) {
Console.WriteLine("Listening on port {0}, and providing WebSocket services:", wssv.Port);
foreach (var path in wssv.WebSocketServices.Paths) {
Console.WriteLine("- {0}", path);
}
}
//WebSocketServer 停止行為
Console.WriteLine("\nPress Enter key to stop the server...");
Console.ReadLine();
MessageQueueSingleton.Instance().FreeQueue(); //清除MessageQueue內所有資料
msgCreater.Abort();// 停用廣播訊息產生執行緒
wssv.Stop();
}
}
}
Client端 程式
<html>
<head>
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="連線" v-on:click="_fnConnect">
<input type="button" value="關閉" v-on:click="_fnClose"><br />
Status : {{ status }}<br />
Revice count : {{ reciveCount }}<br />
Revice Msg : <br />
{{ message }}
</div>
<script>
var websocket; //websocket物件
var app = new Vue({
el: '#app',
data: {
message: '',
reciveCount: 0,
status: 'Disconnected',
WS_Uri:'ws://localhost:55688/Broadcast/'
}, methods: {
_fnConnect: function () {
websocket = new WebSocket(this.WS_Uri);
websocket.binaryType = "arraybuffer";
//會話建立後事件
websocket.onopen = function (evt) {
app._data.status = 'Connected';
};
//會話結束後事件
websocket.onclose = function (evt) {
app._data.status = 'Disconnected';
};
//接收到訊息後事件
websocket.onmessage = function (evt) {
app._data.reciveCount += 1;
app._data.message = new TextDecoder("utf-8").decode(evt.data);;
};
//發生錯誤後事件
websocket.onerror = function (evt) {
app._data.status = evt.data;
};
},
_fnClose: function () {
//會話關閉
websocket.close();
}
}
})
</script>
</body>
</html>
Demo
https://drive.google.com/file/d/1EX1Pifqq86B8S7Rp9eTUeAGL5zIH-U6P/view?usp=sharing
Download
https://drive.google.com/file/d/1DDHI2Y8HQ_z_cgTftiHsbwcT0Yv5l-G6/view?usp=sharing
egan2608@gmail.com