HTML5示例之WebSocket

Web应用程序通常有一些耗时的操作,但有些操作耗时不是很长,一分钟之内能完成。如果采用后台任务队列去异步处理,这样的用户不能实时看到后台处理的情况。倘若用户触发操作后,Web页面能够实时看到后台处理的进度,并且返回实时的状态,用户等待起来是不是感觉非常棒。下面是一个HTML5+ASP.NET MVC实现的示例。

1.前端页面和脚本

页面包含一个文本框和一个【提交】按钮,文本框输入后台要返回的消息数。

<h2>WebSocket</h2>
<div class="form-inline">
    <div class="form-group">
        <label for="count">消息数</label>
        <input type="text" class="form-control" id="count" placeholder="服务端返回的消息数">
    </div>
    <button class="btn btn-primary" onclick="wsTest()">提交</button>
</div>
<blockquote>
    <ol id="msg"></ol>
</blockquote>

WebSocket的api很简单,如下示例封装了一个简单的操作。

var WsUtil = {
    msg: document.getElementById('msg'),
    ws: null,
    connect: function (url, callback) {
        var _this = this;
        _this.msg.innerHTML = '';
        _this.appendMsg('正在连接......', '#00f');
        _this.ws = new WebSocket(url);
        _this.ws.onopen = function () {
            _this.appendMsg('客户端已连接', '#00f');
            if (callback) {
                callback(_this.ws);
            }
        }
        _this.ws.onmessage = function (evt) {
            _this.appendMsg(evt.data);
        }
        _this.ws.onclose = function () {
            _this.appendMsg('客户端已断开连接', '#00f');
        }
        _this.ws.onerror = function (evt) {
            _this.appendMsg(evt.data, '#f00');
        }
    },
    close: function () {
        if (this.ws) {
            this.ws.close();
            this.ws = null;
        }
    },
    appendMsg: function (message, color) {
        var li = document.createElement('li');
        li.style.color = color || '#000';
        li.innerHTML = message;
        msg.appendChild(li);
    }
}

function wsTest() {
    var count = document.getElementById('count').value;
    var url = 'ws://localhost:90/html5/wstask?count=' + count;
    WsUtil.connect(url, function (ws) {
        ws.send('test');
    });
}

2.ASP.NET MVC后端实现WebSocket请求

ASP.NET MVC控制器

public class Html5Controller : Controller
{
    public void WsTask()
    {
        HttpContext.AcceptWebSocketRequest(ctx =>
        {
            int.TryParse(ctx.QueryString["count"], out int count);
            return WebSocketManager.RunTask(ctx, wsm =>
            {
                for (int i = 0; i < count; i++)
                {
                    var message = string.Format("{0:yyyyMMdd HH:mm:ss} 消息{1}", DateTime.Now, i + 1);
                    wsm.SendMessageAsync(message);
                    Thread.Sleep(1000);
                }
            });
        });
    }
}

这里封装了一个WebSocket管理者类。

public class WebSocketManager
{
    private WebSocket socket;

    public WebSocketManager()
    {
    }

    public WebSocketManager(WebSocket socket)
    {
        this.socket = socket;
    }

    public static async Task RunTask(AspNetWebSocketContext context, Action<WebSocketManager> action)
    {
        var socket = context.WebSocket;
        if (socket.State == WebSocketState.Open)
        {
            var wsm = new WebSocketManager(socket);
            try
            {
                action(wsm);
            }
            catch (Exception ex)
            {
                await wsm.SendMessageAsync(ex.Message);
            }
        }
    }

    public Task SendMessageAsync(string message)
    {
        var content = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message));
        return socket.SendAsync(content, WebSocketMessageType.Text, true, CancellationToken.None);
    }
}

3.运行效果

posted @ 2018-01-19 22:31  known  阅读(757)  评论(0编辑  收藏  举报