Wcf中部署WebSocket

前言:最近接手了新的项目,一个MVC的Web端页面实时监控并控制着多台机器上面的多个应用程序,及分布式管理,而每台机器上面的应用都部署在计划任务上面,这里用到任务调度器,后边会更新一篇文章来介绍任务调度器在这里边的用法,每台机器上面都部署一个Wcf服务,即时通信用的SignalR也部署在Wcf中,接手的第一个任务就是把SignalR换成WebSocket。要求:每个应用程序就是一个客户端,web也是客户端,实现客户端对客户端发送消息,而每台机器上要有一个SocketServer的服务端,这样就避免了高并发;WebSocket框架我选的是Fleck简单易用,单个并发量达到6万多上限也是够用了,再加上异步就绰绰有余。

引包:

Wcf中部署WebSocket

因为是在Wcf中部署,所以只需在每次启动服务时打开websocket连接即可:

Wcf中部署WebSocket
static List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();

        public SpiderMonitor()
        {

            var server = new WebSocketServer(AppSettings.SocketUrl);

            server.RestartAfterListenError = true;
            server.Start(socket =>
            {

                socket.OnOpen = () =>
                {
                    allSockets.Add(socket);
                };
                socket.OnClose = () =>
                {
                    allSockets.Remove(socket);
                };
                socket.OnMessage = message =>
                {
                    allSockets.ToList().ForEach(s => s.Send(message));
                };
            });
        }
View Code

服务端部署好以后就是客户端了,因为是分布式,所以每台机器都有一个wcf服务,每个服务里面有一个server服务端;

客户端代码:

Wcf中部署WebSocket
function handler(e) {
            //console.log(e.data);
            //日志[0]  id[1]    信息[2]   CreateDate[3]
            var reg = RegExp(/日志/);
            if (e.data.match(reg)) {
                var str = e.data.split("*");
                console.log(str[2]);


                //将item加入到日志中
                if (app.log[0].TaskId == str[1]) {
                    app.log[0].Description = str[2];
                    var date = new Date(str[3]);
                    app.log[0].CreateDate = date;
                }

                //将任务启动和停止添加到实时信息中
                if (str[2] == 'start' || str[2] == 'end') {
                    var len = app.task.length;
                    for (var idx = 0; idx < len; idx++) {
                        if (app.task[idx].Id == str[1]) {
                            app.task[idx].Status = str[2];
                            break;
                        }
                    }
                }
                //任务开始(收到start消息页面按钮开始)   
                if (str[2] == 'start') {

                    var len = app.task.length;
                    for (var idx = 0; idx < len; idx++) {
                        if (app.task[idx].Id == str[1]) {
                            app.task[idx].State = 'Running';
                            break;
                        }
                    }
                }
                //任务停止(收到end消息页面按钮停止)
                if (str[2] == 'end') {

                    //$.getJSON(path + 'monitor/stop?id=' + str[1]);
                    var len = app.task.length;
                    for (var idx = 0; idx < len; idx++) {
                        if (app.task[idx].Id == str[1]) {

                            app.task[idx].State = 'Ready';
                            break;
                        }
                    }
                    $.getJSON(path + 'monitor/getlog?id=' + str[1], function (d) {
                        app.log = d;
                    });

                }
            }

            //爬取的信息
            var str = e.data.split("*");
            var id = str[0];
            var Data = str[1];
            console.log(Data);
            var len = app.task.length;
            for (var idx = 0; idx < len; idx++) {
                if (app.task[idx].Id == id) {
                    app.task[idx].Status = Data;
                    break;
                }
            }


        }

        var lockReconnect = false;  //避免ws重复连接
        var ws = null;          // 判断当前浏览器是否支持WebSocket
        //var wsUrl = serverConfig.socketUrl;
        //createWebSocket(wsUrl);   //连接ws

        function createWebSocket(url) {
            try {
                if ('WebSocket' in window) {
                    ws = new WebSocket(url);
                    
                }
                initEventHandle(url);
            } catch (e) {
                reconnect(url);
                console.log(e);
            }
        }

        function initEventHandle(url) {
            ws.onclose = function () {
                reconnect(url);
                console.log(url+" "+"连接关闭!" + new Date().toLocaleString());
            };
            ws.onerror = function (e) {
                reconnect(url);
                console.log(url+" "+"连接错误!"+ e.reason);
            };
            ws.onopen = function () {
                console.log(url+" "+"连接成功!" + new Date().toLocaleString());
            };
            ws.onmessage = handler;
        }
        // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function () {
            ws.close();
        }

        function reconnect(url) {
            if (lockReconnect) return;
            lockReconnect = true;
            setTimeout(function () {     //没连接上会一直重连,设置延迟避免请求过多
                createWebSocket(url);
                lockReconnect = false;
            }, 1000);
        }



        //WebSocket将信息和日志实时推送上来;
        $(function () {
            var strArray = new Array();
            strArray.push('ws://10.88.22.27:5008');
            strArray.push('ws://10.88.22.82:5008');
            strArray.push('ws://10.88.22.38:5008');
            strArray.push('ws://10.88.22.62:5008');
            strArray.push('ws://10.88.22.70:5008');
            strArray.push('ws://10.88.22.19:5008');
            strArray.push('ws://10.88.22.30:5008');
            strArray.push('ws://10.88.22.12:5008');
            for (var i = 0; i < strArray.length; i++) {

                createWebSocket(strArray[i]);
                //console.log(strArray[i] + "开始创建连接");
            }
        });
View Code

前端使用的是Vue,所以数据绑定看似跟其他不一样。

最后发布出来上线时,websocket连接使用规则要跟你的项目的IP一致;即当你项目ip是localhost时,websocket链接也是本地IP,发布上线时同理;

还有一个很重要的,websocket发布时必须绕过代理,否则会连接不上;

Wcf中部署WebSocket

 

效果:

Wcf中部署WebSocket

 

这里的websocket链接如果不发送消息只能保持一分钟,一分钟后自动断开;如果想长时间保持连接可以定时发送一些空的信息

 

上一篇:rabbitmq websocket stomp 错误payload=Access refused for user 'guest'


下一篇:【自用】Spring Boot使用WebSocket