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

新建一個類,包含以下代碼,代碼大部分都寫了注釋:
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ù)異常,請檢查端口是否被占用:\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)聽其他請求
            HttpListenerRequest req = context.Request; //獲取連接請求體
            if (req.HttpMethod == "GET") //SSE只接受GET請求
            {
                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ù)運行完畢
                        }
                    }
                }
            }
        }
    }總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
 win7中C#的winForm編程使用savefiledialog不能彈出保存窗體的解決方法
這篇文章主要介紹了win7中C#的winForm編程使用savefiledialog不能彈出保存窗體的解決方法,涉及針對線程的調(diào)用問題,是比較實用的技巧,需要的朋友可以參考下2014-12-12

