1. 程式人生 > >.NetCore WebSocket簡單實現

.NetCore WebSocket簡單實現

專案需要使用.net core的webapi後臺處理一個大檔案,同時向客戶端實時返回處理進度。所以實現了一個簡單demo,記錄一下。

一、服務端

  1. 新建了一個handler

2.SocketHandler.cs內容如下

using DotnetCoreWebAPI.Common;
using DotnetCoreWebAPI.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DotnetCoreWebAPI.Handler
{
    public class SocketHandler
    {
        public const int BufferSize = 4096;
        public string basestringjson = string.Empty;

        WebSocket socket;

        SocketHandler(WebSocket socket)
        {
            this.socket = socket;
        }

        async Task EchoLoop()
        {
            var buffer = new byte[BufferSize];
            var seg = new ArraySegment<byte>(buffer);


            while (this.socket.State == WebSocketState.Open)
            {
                var incoming = await this.socket.ReceiveAsync(seg, CancellationToken.None);
                string receivemsg = Encoding.UTF8.GetString(buffer, 0, incoming.Count);
                if (receivemsg == "get")
                {
                    string stringJson = "";

                    List<AddressMatchProgressModel> infolist = new List<AddressMatchProgressModel>();
                    Hashtable newtable = CommonInfo.ProgressInfo;
                    if (newtable != null)
                    {
                        try
                        {
                            foreach (DictionaryEntry i in newtable)
                            {
                                AddressMatchProgressModel pgmodel = new AddressMatchProgressModel();
                                pgmodel = (AddressMatchProgressModel)i.Value;
                                infolist.Add(pgmodel);
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    stringJson = JsonConvert.SerializeObject(infolist);


                    string userMsg = stringJson;
                    byte[] x = Encoding.UTF8.GetBytes(userMsg);
                    var outgoing = new ArraySegment<byte>(x);
                    await this.socket.SendAsync(outgoing, WebSocketMessageType.Text, true, CancellationToken.None);
                }
                //var incoming = await this.socket.ReceiveAsync(seg, CancellationToken.None);
                //var outgoing = new ArraySegment<byte>(buffer, 0, incoming.Count);
                //await this.socket.SendAsync(outgoing, WebSocketMessageType.Text, true, CancellationToken.None);

            }
        }

        static async Task Acceptor(HttpContext hc, Func<Task> n)
        {
            if (!hc.WebSockets.IsWebSocketRequest)
                return;

            var socket = await hc.WebSockets.AcceptWebSocketAsync();
            var h = new SocketHandler(socket);
            await h.EchoLoop();
        }

        /// <summary>
        /// branches the request pipeline for this SocketHandler usage
        /// </summary>
        /// <param name="app"></param>
        public static void Map(IApplicationBuilder app)
        {
            app.UseWebSockets();
            app.Use(SocketHandler.Acceptor);
        }
    }
}

(ps:這裡遇到了一個小問題 ,記錄一下。我在另一個地方處理大檔案的,並把處理進度實時更新在一個全域性變數hashtable裡,然後在websocket服務端獲取這個變數的值,從而得到處理進度主動推送給客戶端。問題是hashtable在不斷的寫入同時在讀取,有時候便會出現movenext異常了。所以這裡將全域性變數hashtable賦值給了一個新的hashtable,這樣就可以保證在websocket服務端獲取進度資料的時候,這個hasntable的值是不會在遍歷的過程中變化的。)

3.startup.cs新增路由


 二、客戶端

客戶端js指令碼寫的

//啟動websocket
                function startWebsocket() {
                    var ws = new WebSocket("ws://localhost:9957/ws");
                    ws.onopen = function (evt) {
                        console.log("Connection open ...");
                        isOpenWebSocket = true;
                        ws.send("get");
                    };
                    ws.onmessage = function (evt) {
                        isOpenWebSocket = true;
                        console.log("Received Message: " + evt.data);
                        var data = $.parseJSON(evt.data);
                        if (data.length > 0) {

                            var allfinish = true;
                            for (var num in data) {
                                var gid = data[num].Gid;
                                var fileName = data[num].UploadFileName;
                                var progress = data[num].Progress;
                                if ($("#" + gid).length <= 0) {
                                    //當前進度條不存在
                                    $("#progressbox").append("<div class='progress onepro' ><div id='" + gid + "' class='progress-bar' role='progressbar' aria-valuenow='60' aria-valuemin='0' aria-valuemax='100' style='width: 0%;'></div></div ><div id='" + gid + "_span' class='infospan'>" + fileName + "處理中</div ><div class='clearfloat'></div>");

                                }
                                $("#" + gid).css("width", progress + "%").val("aria-valuenow", progress);

                                if (progress == "100") {
                                    $("#" + gid + "_span").html(fileName + '處理完成,<a class="downloada" onclick="clickdown('' + gid + '')">下載</a>');
                                } else {
                                    allfinish = false;
                                }
                            }

                            if (allfinish) {
                                //進度全部100%
                                ws.close();
                                isOpenWebSocket = false;
                            } else {
                                ws.send("get");
                            }

                        } else {
                            //進度資料不存在,斷開連線
                            ws.close();
                            isOpenWebSocket = false;
                        }

                        //ws.send("");

                    };
                    ws.onclose = function (evt) {
                        isOpenWebSocket = false;
                        console.log("Connection closed.");
                    };
                    ws.onerror = function (evt) {
                        write("Error: " + evt.data);
                    };
                    //強制關閉瀏覽器  呼叫websocket.close(),進行正常關閉
                    window.onunload = function () {
                        ws.close();
                        isOpenWebSocket = false;
                    }
                }