WebSocket使用SuperWebSocket結合WindowsService實現實時消息

SuperWebSocket在WebService中的應用

最開始使用是寄託在IIS中,發佈以後測試時半個小時就會斷開,因此改成WindowsServicehtml

1. 新建Windows服務項目【TestWindowsService】,重命名Service1爲MyWebSocketService

2. 打開MyWebSocketService設計視圖,右鍵,添加安裝程序,自動添加ProjectInstaller.cs。

打開設計視圖,選中ServiceInstaller1,右鍵修改屬性:web

  • ServiceName(服務名):這裏改成咱們剛重命名的MyWebSocketService
  • StartType(啓動方式):改成自動啓動Automatic
  • DelayedAutoStart(延遲加載)

選中serviceProcessInstaller1,右鍵修改屬性:windows

  • Account(帳戶類型):這裏改成LocalSystem

3. 添加安裝和卸載文件。注意添加文件請使用ANSI編碼。推薦使用EditPlus等工具新建文件,而後經過項目添加現有項。

注意替換TestWindowsService.exe和MyWebSocketService。右鍵屬性,設置複製到輸出目錄。瀏覽器

Install.bat:安全

%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe TestWindowsService.exe
sc config MyWebSocketService start= auto 
Net Start MyWebSocketService
pause

Uninstall.bat服務器

%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u TestWindowsService.exe

4. 添加App.config,配置IP和Port。

IP地址爲本地鏈接地址,端口號自定義。確保端口號不被佔用。websocket

<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <appSettings>
    <add key="APWebSocketIP" value="192.168.1.199"/>
    <add key="APWebSocketPort" value="8200"/>
  </appSettings>
</configuration>

5. 修改MyWebSocketService服務代碼。

推薦手動加載dll,經過Nuget加載時,添加依賴的Log4net版本與SuperWebSocket中調用的Log4net版本存在衝突。
log4net版本爲1.2.11.0session

項目右鍵,管理Nuget程序包,搜索SuperWebSocket,注意做者爲Kerry Jiang。
app

WebSocketServer server;
        protected override void OnStart(string[] args)
        {
            var ip = ConfigurationManager.AppSettings["APWebSocketIP"];
            var port = ConfigurationManager.AppSettings["APWebSocketPort"];
            //WebSocket服務器端啓動
            server = new WebSocketServer();
            if (!server.Setup(ip, int.Parse(port)))
            {
                //Debug.Write("WebSocket服務器端啓動失敗");
                //處理啓動失敗消息
                return;
            }

            //新的會話鏈接時
            server.NewSessionConnected += server_NewSessionConnected;
            //會話關閉
            server.SessionClosed += server_SessionClosed;
            //接收到新的消息時
            server.NewMessageReceived += server_NewMessageReceived;

            if (!server.Start())
            {
                //Debug.Write(string.Format("開啓WebSocket服務偵聽失敗:{0}:{1}", server.Config.Ip, server.Config.Port));
                //處理監聽失敗消息
                return;
            }
        }


        string KSessionId;
        string VSessionId;
        Dictionary<string, List<string>> msgDictionary = new Dictionary<string, List<string>>();
        private void server_NewMessageReceived(WebSocketSession session, string value)
        {
            Debug.WriteLine("接收到新的消息:{0}  來自:{1}  時間:{2:HH:MM:ss}", value, session.RemoteEndPoint, DateTime.Now);
            if (value.StartsWith("K"))
            {
                KSessionId = session.SessionID;
                //頁面已連接
                if (!String.IsNullOrEmpty(VSessionId))
                    SendMsgToRemotePoint(VSessionId, string.Format("考場發來消息:{0}", value));
                //頁面未連接
                else
                {
                    AddMsgToSessionId(VSessionId);
                }
            }
            else if (value.StartsWith("S"))
            {
                VSessionId = session.SessionID;
                //考場已連接
                if (!String.IsNullOrEmpty(KSessionId))
                    SendMsgToRemotePoint(KSessionId, string.Format("學生A發來消息:{0}", value));
                //考場已斷開
                else
                {
                    AddMsgToSessionId(KSessionId);
                }
            }

        }

        /// <summary>
        /// 添加會話消息
        /// </summary>
        /// <param name="value"></param>
        private void AddMsgToSessionId(string value)
        {
            if (value != null)
            {
                //消息列表包含頁面會話ID
                if (msgDictionary.ContainsKey(value))
                {
                    msgDictionary[value].Add(value);
                }
                //消息列表不包含頁面會話ID
                else
                    msgDictionary.Add(value, new List<string>() { value });
            }
        }

        /// <summary>
        /// 會話關閉
        /// </summary>
        /// <param name="session"></param>
        /// <param name="value"></param>
        private void server_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value)
        {
            Debug.WriteLine("會話關閉,關閉緣由:{0}  來自:{1}  時間:{2:HH:MM:ss}", value, session.RemoteEndPoint, DateTime.Now);
            if (session.SessionID == KSessionId)
                SendMsgToRemotePoint(VSessionId, "考場已斷開");
            else if (session.SessionID == VSessionId)
                SendMsgToRemotePoint(KSessionId, "學生A已斷開");
        }

        /// <summary>
        /// 新的會話連接
        /// </summary>
        /// <param name="session"></param>
        private void server_NewSessionConnected(WebSocketSession session)
        {
            Debug.WriteLine("新的會話鏈接  來自:{0} SessionID:{1}  時間:{2:HH:MM:ss}", session.RemoteEndPoint, session.SessionID, DateTime.Now);
            if (msgDictionary.ContainsKey(session.SessionID))
                msgDictionary[session.SessionID].ForEach(item => session.Send(item));
        }

        /// <summary>
        /// 發送消息到
        /// </summary>
        /// <param name="sessionId"></param>
        /// <param name="msg"></param>
        private void SendMsgToRemotePoint(string sessionId, string msg)
        {
            var allSession = server.GetAppSessionByID(sessionId);
            if (allSession != null)
                allSession.Send(msg);
        }

6.添加log4net配置文件log4net.config。查看日誌。

因爲SuperWebSocket已經有日誌功能,只須要添加配置文件,便可查看日誌。socket

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
    <appender name="errorAppender" type="log4net.Appender.RollingFileAppender">
        <filter type="log4net.Filter.LevelMatchFilter">
            <levelToMatch value="ERROR" />
        </filter>
        <filter type="log4net.Filter.DenyAllFilter" />
        <File value="Logs\err.log" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <datePattern value="yyyyMMdd" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
        </layout>
    </appender>
    <appender name="infoAppender" type="log4net.Appender.RollingFileAppender">
        <filter type="log4net.Filter.LevelMatchFilter">
            <levelToMatch value="INFO" />
        </filter>
        <filter type="log4net.Filter.DenyAllFilter" />
        <File value="Logs\info.log" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <datePattern value="yyyyMMdd" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
        </layout>
    </appender>
    <appender name="debugAppender" type="log4net.Appender.RollingFileAppender">
        <filter type="log4net.Filter.LevelMatchFilter">
            <levelToMatch value="DEBUG" />
        </filter>
        <filter type="log4net.Filter.DenyAllFilter" />
        <File value="Logs\debug.log" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <datePattern value="yyyyMMdd" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
        </layout>
    </appender>
    <appender name="perfAppender" type="log4net.Appender.RollingFileAppender">
        <filter type="log4net.Filter.LevelMatchFilter">
            <levelToMatch value="INFO" />
        </filter>
        <filter type="log4net.Filter.DenyAllFilter" />
        <File value="Logs\perf.log" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <datePattern value="yyyyMMdd" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%date %logger - %message%newline" />
        </layout>
    </appender>
    <root>
        <level value="ALL" />
        <appender-ref ref="errorAppender" />
        <appender-ref ref="infoAppender" />
        <appender-ref ref="debugAppender" />
    </root>
    <logger name="Performance" additivity="false">
      <level value="ALL" />
      <appender-ref ref="perfAppender" />
    </logger>
</log4net>

在html中使用WebSocket

1.首先考慮瀏覽器兼容問題。一些低版本瀏覽器不支持。

2.建立websocket對象,設置ip和端口。

var ws;
var url = "ws://192.168.1.199:8200";

$("#btnConnection").click(function () {
    if ("WebSocket" in window) {
        ws = new WebSocket(url);
    }
    else if ("MozWebSocket" in window) {
        ws = new MozWebSocket(url);
    }
    else
        alert("瀏覽器版本太低,請升級您的瀏覽器。\r\n瀏覽器要求:IE10+/Chrome14+/FireFox7+/Opera11+");

    //註冊各種回調
    ws.onopen = function () {
        $("#msg").append("鏈接服務器成功<br/>");
        ws.send("S:學生A已連接");
    }

    ws.onclose = function () {
        $("#msg").append("與服務器斷開鏈接<br/>");
    }
    ws.onerror = function () {
        $("#msg").append("數據傳輸發生錯誤<br/>");
    }
    ws.onmessage = function (receiveMsg) {
        $("#msg").append(receiveMsg.data + "<br/>");
    }
});

這裏模擬一個學生A和考場的交互。

首先鏈接考場。

接着鏈接考生。

考場發送消息,通知學生開始考試。

學生接到消息,開始答題。

考試收到考生開始答題消息。

發佈

1.首先拷貝TestWebService中的bin\Debug|Release中生成的文件到服務器。經過開始→運行→cmd→ipconfig,查看服務器的本地連接地址(192開頭)。修改App.config中的IP和端口號。

2.雙擊Install.bat文件,等待安裝服務。

3.修改html中的WebSocket對象的ip和端口號。這裏的ip爲服務器固定ip,與WebSocket配置不一樣。

4.若是涉及到讀寫文件,請在服務器端類360安全衛士等軟件添加信任。

經過Install.bat沒法啓動時,能夠查看本地日誌文件和控制面板的事件管理器,定位詳細錯誤。

源代碼下載:TestWebSocket.zip
轉載請註明出處:http://xcong.cnblogs.com

相關文章
相關標籤/搜索