C#下如何實(shí)現(xiàn)Server-Sent Event(SSE)
1.引言
最近有個(gè)C#項(xiàng)目需要實(shí)現(xiàn)SSE服務(wù),但在網(wǎng)上找了一圈都沒有相關(guān)的文章,那就只能根據(jù)服務(wù)的協(xié)議自己寫了。
在這里分享下,希望能幫助有需要的開發(fā)者。
2.功能實(shí)現(xiàn)
項(xiàng)目要求不高,不要求每次傳輸?shù)臄?shù)據(jù)必達(dá)客戶端,即不追求穩(wěn)定性,因此在功能實(shí)現(xiàn)上我使用HttpListener庫作為功能的服務(wù)端。
相關(guān)協(xié)議內(nèi)容請(qǐng)自行參照EventSource - Web API 接口參考 | MDN (mozilla.org)
各瀏覽器的支持情況:

新建一個(gè)類,包含以下代碼,代碼大部分都寫了注釋:
class SSEServer {
private static HttpListener listener;
public bool Start() {
try {
listener = new HttpListener();
listener.Prefixes.Add($ "http://+:{Properties.Settings.Default.ServerPort}/"); // 監(jiān)聽配置文件中的IP地址,必須以`/`結(jié)尾
listener.Start();
listener.BeginGetContext(GetContentCallBack, listener); //當(dāng)創(chuàng)建連接后響應(yīng)的函數(shù)
} catch (Exception ex) {
MessageBox.Show("創(chuàng)建服務(wù)異常,請(qǐng)檢查端口是否被占用:\n" + ex);
return false;
}
return true;
}
public void Stop() {
if (listener.IsListening) {
listener.Stop();
}
}
private void GetContentCallBack(IAsyncResult ar) {
HttpListener _listener = ar.AsyncState as HttpListener; //異步服務(wù),避免阻塞,也能接收多條連接
if (_listener.IsListening) {
HttpListenerContext context = _listener.EndGetContext(ar);
_listener.BeginGetContext(new AsyncCallback(GetContentCallBack), _listener); // 創(chuàng)建新線程監(jiān)聽其他請(qǐng)求
HttpListenerRequest req = context.Request; //獲取連接請(qǐng)求體
if (req.HttpMethod == "GET") //SSE只接受GET請(qǐng)求
{
HttpListenerResponse response = context.Response; //獲取連接響應(yīng)體
response.StatusCode = (int) HttpStatusCode.OK; //設(shè)定狀態(tài)碼
response.ContentType = "text/event-stream;charset=UTF-8"; //設(shè)定SSE的響應(yīng)頭
response.AddHeader("Cache-Control", "no-cache");
response.AddHeader("Connection", "keep-alive");
response.AddHeader("Access-Control-Allow-Origin", "*");
response.AddHeader("Transfer-Encoding", "chunked");
response.ContentEncoding = Encoding.UTF8; //各種各樣的響應(yīng)頭
using(var stream = response.OutputStream) { //創(chuàng)建響應(yīng)體自帶的緩存流
while (true) {
try {
var data = Encoding.UTF8.GetBytes($ "Event: message\ndata: Hello World!\n\n"); //必須以UTF8編碼發(fā)送數(shù)據(jù)
stream.Write(data, 0, data.Length);
Thread.Sleep(1000); //一秒發(fā)送一次數(shù)據(jù)
} catch { //有問題直接catch
}));
}
_listener.Close(); //關(guān)閉當(dāng)前線程的連接
break; //當(dāng)前連接響應(yīng)函數(shù)運(yùn)行完畢
}
}
}
}
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#把數(shù)字轉(zhuǎn)換成大寫金額的代碼實(shí)例
這篇文章主要介紹了C#把數(shù)字轉(zhuǎn)換成大寫金額的代碼實(shí)例,例如把200轉(zhuǎn)換成“貳佰元”,需要的朋友可以參考下2014-05-05
基于WPF實(shí)現(xiàn)Message消息提醒控件
這篇文章主要介紹了如何利用WPF實(shí)現(xiàn)Meesage消息提醒控件,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定幫助,需要的可以參考一下2023-07-07
win7中C#的winForm編程使用savefiledialog不能彈出保存窗體的解決方法
這篇文章主要介紹了win7中C#的winForm編程使用savefiledialog不能彈出保存窗體的解決方法,涉及針對(duì)線程的調(diào)用問題,是比較實(shí)用的技巧,需要的朋友可以參考下2014-12-12

