.net 4.0以下版本實現web socket服務


直接上代碼:

1. WebSocket.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Reflection;

namespace BH.WebSocketServer
{
    public class WebSocket
    {
        log4net.ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        private Dictionary<string, Session> SessionPool = new Dictionary<string, Session>();
        private Dictionary<string, string> MsgPool = new Dictionary<string, string>();
        private Socket _socket=null;
        public Socket SockeServer
        {
            get
            {
                return this._socket;
            }
        }


        #region 啟動WebSocket服務
        /// <summary>
        /// 啟動WebSocket服務
        /// </summary>
        public void start(int port)
        {
            this._socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SockeServer.Bind(new IPEndPoint(IPAddress.Any, port));
            SockeServer.Listen(20);
            SockeServer.BeginAccept(new AsyncCallback(Accept), SockeServer);
            log.Info("Socket服務已啟動,PORT:"+port);
            Console.WriteLine("服務已啟動");
            Console.WriteLine("按任意鍵關閉服務");

            while (true)
            {
                Thread.Sleep(20 * 1000);
            }
            //this._socket = null;
            log.Info("Socket服務已停止");

        }
        #endregion

        #region 處理客戶端連接請求
        /// <summary>
        /// 處理客戶端連接請求
        /// </summary>
        /// <param name="result"></param>
        private void Accept(IAsyncResult socket)
        {
            // 還原傳入的原始套接字
            Socket SockeServer = (Socket)socket.AsyncState;
            // 在原始套接字上調用EndAccept方法,返回新的套接字
            Socket SockeClient = SockeServer.EndAccept(socket);
            byte[] buffer = new byte[4096];
            try
            {
                //接收客戶端的數據
                SockeClient.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient);
                //保存登錄的客戶端
                Session session = new Session();
                session.SockeClient = SockeClient;
                session.IP = SockeClient.RemoteEndPoint.ToString();
                session.buffer = buffer;
                lock (SessionPool)
                {
                    if (SessionPool.ContainsKey(session.IP))
                    {
                        this.SessionPool.Remove(session.IP);
                    }
                    this.SessionPool.Add(session.IP, session);
                }
                //准備接受下一個客戶端
                SockeServer.BeginAccept(new AsyncCallback(Accept), SockeServer);
                Console.WriteLine(string.Format("Client {0} connected", SockeClient.RemoteEndPoint));
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : " + ex.ToString());
            }
        }
        #endregion

        public delegate void EventRecieveData(string msg,Socket sockeClient);
        public event EventRecieveData onRecievData;

        #region 處理接收的數據
        /// <summary>
        /// 處理接受的數據
        /// </summary>
        /// <param name="socket"></param>
        private void Recieve(IAsyncResult socket)
        {
            Socket SockeClient = (Socket)socket.AsyncState;
            string IP = SockeClient.RemoteEndPoint.ToString();
            if (SockeClient == null || !SessionPool.ContainsKey(IP))
            {
                return;
            }
            try
            {
                int length = SockeClient.EndReceive(socket);
                byte[] buffer = SessionPool[IP].buffer;
                SockeClient.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient);
                string msg = Encoding.UTF8.GetString(buffer, 0, length);
                //  websocket建立連接的時候,除了TCP連接的三次握手,websocket協議中客戶端與服務器想建立連接需要一次額外的握手動作
                if (msg.Contains("Sec-WebSocket-Key"))
                {
                    SockeClient.Send(PackageHandShakeData(buffer, length));
                    SessionPool[IP].isWeb = true;
                    return;
                }
                if (SessionPool[IP].isWeb)
                {
                    msg = AnalyzeClientData(buffer, length);
                }
                //byte[] msgBuffer = PackageServerData(msg);
                //foreach (Session se in SessionPool.Values)
                //{
                //    //se.SockeClient.Send(msgBuffer, msgBuffer.Length, SocketFlags.None);
                //}

                if (this.onRecievData!=null)
                {
                    onRecievData(msg,SockeClient);

                }
                //add by mo  這里的msg就是客戶端發過來的消息。要處理就這里寫邏輯代碼。
            }
            catch
            {
                try
                {
                    SockeClient.Disconnect(true);
                    Console.WriteLine("客戶端 {0} 斷開連接", IP);
                    SessionPool.Remove(IP);

                }
                catch (System.Exception ex)
                {
                	
                }

            }
        }
        #endregion

        #region 客戶端和服務端的響應
        /*
         * 客戶端向服務器發送請求
         * 
         * GET / HTTP/1.1
         * Origin: http://localhost:1416
         * Sec-WebSocket-Key: vDyPp55hT1PphRU5OAe2Wg==
         * Connection: Upgrade
         * Upgrade: Websocket
         *Sec-WebSocket-Version: 13
         * User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
         * Host: localhost:8064
         * DNT: 1
         * Cache-Control: no-cache
         * Cookie: DTRememberName=admin
         * 
         * 服務器給出響應
         * 
         * HTTP/1.1 101 Switching Protocols
         * Upgrade: websocket
         * Connection: Upgrade
         * Sec-WebSocket-Accept: xsOSgr30aKL2GNZKNHKmeT1qYjA=
         * 
         * 在請求中的“Sec-WebSocket-Key”是隨機的,服務器端會用這些數據來構造出一個SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一個魔幻字符串
         * “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”。使用 SHA-1 加密,之后進行 BASE-64編碼,將結果做為 “Sec-WebSocket-Accept” 頭的值,返回給客戶端
         */
        #endregion

        #region 打包請求連接數據
        /// <summary>
        /// 打包請求連接數據
        /// </summary>
        /// <param name="handShakeBytes"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private byte[] PackageHandShakeData(byte[] handShakeBytes, int length)
        {
            string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, length);
            string key = string.Empty;
            Regex reg = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
            Match m = reg.Match(handShakeText);
            if (m.Value != "")
            {
                key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
            }
            byte[] secKeyBytes = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
            string secKey = Convert.ToBase64String(secKeyBytes);
            var responseBuilder = new StringBuilder();
            responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + "\r\n");
            responseBuilder.Append("Upgrade: websocket" + "\r\n");
            responseBuilder.Append("Connection: Upgrade" + "\r\n");
            responseBuilder.Append("Sec-WebSocket-Accept: " + secKey + "\r\n\r\n");
            return Encoding.UTF8.GetBytes(responseBuilder.ToString());
        }
        #endregion

        #region 處理接收的數據
        /// <summary>
        /// 處理接收的數據
        /// 參考 http://www.cnblogs.com/smark/archive/2012/11/26/2789812.html
        /// </summary>
        /// <param name="recBytes"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private string AnalyzeClientData(byte[] recBytes, int length)
        {
            int start = 0;
            // 如果有數據則至少包括3位
            if (length < 2) return "";
            // 判斷是否為結束針
            bool IsEof = (recBytes[start] >> 7) > 0;
            // 暫不處理超過一幀的數據
            if (!IsEof) return "";
            start++;
            // 是否包含掩碼
            bool hasMask = (recBytes[start] >> 7) > 0;
            // 不包含掩碼的暫不處理
            if (!hasMask) return "";
            // 獲取數據長度
            UInt64 mPackageLength = (UInt64)recBytes[start] & 0x7F;
            start++;
            // 存儲4位掩碼值
            byte[] Masking_key = new byte[4];
            // 存儲數據
            byte[] mDataPackage;
            if (mPackageLength == 126)
            {
                // 等於126 隨后的兩個字節16位表示數據長度
                mPackageLength = (UInt64)(recBytes[start] << 8 | recBytes[start + 1]);
                start += 2;
            }
            if (mPackageLength == 127)
            {
                // 等於127 隨后的八個字節64位表示數據長度
                mPackageLength = (UInt64)(recBytes[start] << (8 * 7) | recBytes[start] << (8 * 6) | recBytes[start] << (8 * 5) | recBytes[start] << (8 * 4) | recBytes[start] << (8 * 3) | recBytes[start] << (8 * 2) | recBytes[start] << 8 | recBytes[start + 1]);
                start += 8;
            }
            mDataPackage = new byte[mPackageLength];
            for (UInt64 i = 0; i < mPackageLength; i++)
            {
                mDataPackage[i] = recBytes[i + (UInt64)start + 4];
            }
            Buffer.BlockCopy(recBytes, start, Masking_key, 0, 4);
            for (UInt64 i = 0; i < mPackageLength; i++)
            {
                mDataPackage[i] = (byte)(mDataPackage[i] ^ Masking_key[i % 4]);
            }
            return Encoding.UTF8.GetString(mDataPackage);
        }
        #endregion

        #region 發送數據
        /// <summary>
        /// 把發送給客戶端消息打包處理(拼接上誰什么時候發的什么消息)
        /// </summary>
        /// <returns>The data.</returns>
        /// <param name="message">Message.</param>
        public static byte[] PackageServerData(string msg)
        {
            byte[] content = null;
            byte[] temp = Encoding.UTF8.GetBytes(msg);
            if (temp.Length < 126)
            {
                content = new byte[temp.Length + 2];
                content[0] = 0x81;
                content[1] = (byte)temp.Length;
                Buffer.BlockCopy(temp, 0, content, 2, temp.Length);
            }
            else if (temp.Length < 0xFFFF)
            {
                content = new byte[temp.Length + 4];
                content[0] = 0x81;
                content[1] = 126;
                content[2] = (byte)(temp.Length >> 8);
                content[3] = (byte)(temp.Length & 0xFF);
                Array.Copy(temp, 0, content, 4, temp.Length);
            }
            else
            {
                content = new byte[temp.Length + 10];
                content[0] = 0x81;
                content[1] = 127;
                content[2] = 0;
                content[3] = 0;
                content[4] = 0;
                content[5] = 0;
                content[6] = (byte)(temp.Length >> 24);
                content[7] = (byte)(temp.Length >> 16);
                content[8] = (byte)(temp.Length >> 8);
                content[9] = (byte)(temp.Length & 0xFF);
                Array.Copy(temp, 0, content, 10, temp.Length);
            }
            return content;
        }
        #endregion
    }
}

2. Session.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;

namespace BH.WebSocketServer
{
    public class Session
    {
        private Socket _sockeclient;
        private byte[] _buffer;
        private string _ip;
        private bool _isweb = false;

        public Socket SockeClient
        {
            set { _sockeclient = value; }
            get { return _sockeclient; }
        }

        public byte[] buffer
        {
            set { _buffer = value; }
            get { return _buffer; }
        }

        public string IP
        {
            set { _ip = value; }
            get { return _ip; }
        }

        public bool isWeb
        {
            set { _isweb = value; }
            get { return _isweb; }
        }
    }
}

4. 使用方法

WebSockete服務器類庫:
使用的時候,綁定事件,EventRecieveData處理客戶端發來的消息。
`           WebSocket socket = new WebSocket();
            socket.onRecievData += new WebSocket.EventRecieveData(socket_onRecievData);
            socket.start(要監聽的端口號);

			void socket_onRecievData(string msg, System.Net.Sockets.Socket sockeClient)
			msg就是收到的消息。
			sockeClient是發來消息的客戶


5.使用例子:

以下代碼,做成服務,監聽指定端口

        private void socket_onRecievData(string msg, System.Net.Sockets.Socket sockeClient)
        {
            SendData sd = new SendData();
            //下面的按真實情況返回。這里只是測試
            BH.JsonHelp.SqlResult result = new BH.JsonHelp.SqlResult()
            {
                result = false,
                data = "",
                errorMessage = ""
            };
            sd.data = result;
            try
            {

                string recvMsg = msg;
                RecieveData rd = null;
                try
                {
                   rd= BH.JsonHelp.JsonHelper.DeserializeJsonToObject<RecieveData>(msg);
                }
                catch (System.Exception ex)
                {
                    LogOuts.Info("msg:" + msg);
                }
                if (rd == null)
                {
                    throw new Exception("收到數據格式不對:"+msg);
                }
                int funcId = rd.functionId;
                string recvData = rd.data;

                //讀取到的所有EPC標簽
                List<string> listRecv = new List<string>();
                string errMsg = string.Empty;
                //回寫給客戶端
                sd.functionId = rd.functionId;
                switch (rd.functionId)
                {
                    case 1:
                        //讀卡的邏輯
                        result.result = GetEPCInventory(out listRecv, out errMsg);

                        if (result.result)
                        {
                            if (listRecv.Count != 1)
                            {
                                if (listRecv.Count > 1)
                                {
                                    result.result = false;
                                    result.errorMessage = "讀卡器讀取的標簽超過一張";
                                }
                                else if (listRecv.Count == 0)
                                {
                                    result.result = false;
                                    result.errorMessage = "讀卡器附近沒有標簽可操作";
                                }
                            }
                            else
                            {
                                string cardData = "";


                                //以下代碼讀數據是OK的。
                                //循環讀取確保能讀到數據
                                for (int i = 0; i < 10; i++)
                                {
                                    result.result = ReadEPCTag(listRecv[0], out cardData, out errMsg);
                                    if (result.result)
                                    {
                                        result.data = cardData;
                                        result.errorMessage = listRecv[0];
                                    }
                                    else
                                    {
                                        result.result = false;
                                        result.errorMessage = errMsg;
                                    }
                                    if (cardData != "")
                                    {
                                        break;
                                    }
                                }
                                //end   


                                /*result.result = ReadEPCTag(listRecv[0], out cardData, out errMsg);
                                if (result.result)
                                {
                                    result.errorMessage = listRecv[0];
                                    result.data = cardData;
                                }
                                else
                                {
                                    result.result = false;
                                    result.errorMessage = errMsg;
                                }*/
                            }
                        }
                        else
                        {
                            result.errorMessage = errMsg;
                        }

                        break;
                    case 2:
                        //寫卡的邏輯。
                        result.result = GetEPCInventory(out listRecv, out errMsg);
                        if (result.result)
                        {
                            if (listRecv.Count != 1)
                            {
                                if (listRecv.Count > 1)
                                {
                                    result.result = false;
                                    result.errorMessage = "讀卡器讀取的標簽超過一張";
                                }
                                else if (listRecv.Count == 0)
                                {
                                    result.result = false;
                                    result.errorMessage = "讀卡器附近沒有標簽可操作";
                                }
                            }
                            else
                            {
                                if (string.IsNullOrEmpty(recvData))
                                {
                                    result.result = false;
                                    result.errorMessage = "標簽寫入內容不能為空,請輸入一些內容!";
                                }
                                else
                                {
                                    recvData = recvData.Replace(" ", "").Replace("\r\n", "");

                                    //加循環確保寫入成功
                                    for (int i = 0; i < 10; i++)
                                    {
                                        result.result = WriteEPCTag(listRecv[0], recvData, out errMsg);
                                        if (result.result)
                                        {
                                            result.data = listRecv[0];
                                            result.errorMessage = listRecv[0];
                                            break;
                                        }
                                        else
                                        {
                                            result.result = false;
                                            result.errorMessage = errMsg;
                                        }
                                    }

                                    /*result.result = WriteEPCTag(listRecv[0], recvData, out errMsg);
                                    if (result.result)
                                    {
                                        result.data = listRecv[0];
                                        result.errorMessage = "標簽寫入成功!";
                                    }
                                    else
                                    {
                                        result.result = false;
                                        result.errorMessage = errMsg;
                                    }*/
                                }
                            }
                        }
                        else
                        {
                            result.errorMessage = errMsg;
                        }

                        break;
                    case 3:
                        //獲取標簽ID
                        result.result = GetEPCInventory(out listRecv, out errMsg);

                        if (result.result)
                        {
                            if (listRecv.Count != 1)
                            {
                                if (listRecv.Count > 1)
                                {
                                    result.result = false;
                                    result.errorMessage = "讀卡器讀取的標簽超過一張";
                                }
                                else if (listRecv.Count == 0)
                                {
                                    result.result = false;
                                    result.errorMessage = "讀卡器附近沒有標簽可操作";
                                }
                            }
                            else
                            {
                                string cardData = "";


                                // edit my mo 2021-1-6 不讀取數據。直接返加ID
                                result.result = true;
                                result.errorMessage = listRecv[0];
                                //以下代碼讀數據是OK的。
                                //循環讀取確保能讀到數據
                                //for (int i = 0; i < 10; i++)
                                //{
                                //    result.result = ReadEPCTag(listRecv[0], out cardData, out errMsg);
                                //    if (result.result)
                                //    {
                                //        result.data = cardData;
                                //        result.errorMessage = listRecv[0];
                                //    }
                                //    else
                                //    {
                                //        result.result = false;
                                //        result.errorMessage = errMsg;
                                //    }
                                //    if (cardData != "")
                                //    {
                                //        break;
                                //    }
                                //}
                                //end   


                                /*result.result = ReadEPCTag(listRecv[0], out cardData, out errMsg);
                                if (result.result)
                                {
                                    result.errorMessage = listRecv[0];
                                    result.data = cardData;
                                }
                                else
                                {
                                    result.result = false;
                                    result.errorMessage = errMsg;
                                }*/
                            }
                        }
                        else
                        {
                            result.errorMessage = errMsg;
                        }

                        break;
                }
                //LogOuts.Info("返回結果:" + JsonHelper.SerializeObject(sd));
            }
            catch (System.Exception ex)
            {
                result.errorMessage = ex.Message;
                LogOuts.Info("ex:"+ex.ToString());
            }

            try
            {
                byte[] msgBuffer = BH.WebSocketServer.WebSocket.PackageServerData(JsonHelper.SerializeObject(sd));
                sockeClient.Send(msgBuffer, msgBuffer.Length, SocketFlags.None);
            }
            catch (Exception ex)
            {
                LogOuts.Info(ex.Message.ToString());
            }
        }

        

6. web通過js 連接socket服務。

文件名:
rwinterface.js

var FUNCIDS = {
    _read:1,
	_write:2,
	_getId:3,
};


var SmartReader={
    OBJ:function(){
		var reader={};
		var SocketOpen=false;
		var socket=null;
		var target=null;

        reader.onResult=function(func){
            target.addEvent("Result", func);
        };
        
        var WSonOpen=function(){
            SocketOpen=true;
        };
        var WSonMessage=function(msg){
			//回調定義,返回json,json有一個data字段,是數據
			
			var str = "";
			str = msg.data;
			console.log(str);
			var resultData=eval("("+msg.data+")");
			resultData.type="Result";
			if(target!=null){
				target.fireEvent(resultData);
			}
        };
        var WSonClose=function(){
            SocketOpen=false;
        };
        var WSonError=function(){
			SocketOpen=false;
            //alert("RFID讀寫服務未開啟,先下載服務並安裝!");
        };
        reader.createSocket=function(){
            try{
                if ("WebSocket" in window){
                    socket = new WebSocket("ws://localhost:13001/");
                }
                else if("MozWebSocket" in window){
                    socket = new MozWebSocket("ws://localhost:13001/");
                }
                else{
                    alert("None");
                    return false;
                }
                socket.onopen= WSonOpen;
                socket.onmessage= WSonMessage;
                socket.onclose= WSonClose;
                socket.onerror= WSonError;
                target = new EventTarget();
                return true;
            }
            catch (ex){
                return false;
            }
        };
        reader.Disconnect=function(){
            if(socket!=null)
                socket.close();
        };

		reader.getOBJ = function(id){
			return reader;
		};

        var SendCmd=function(FunctionID, ParamStr){
			var entryCmd;
			if(true == SocketOpen)
			{
				entryCmd = {functionId:FunctionID,data:ParamStr}
				socket.send(JSON.stringify(entryCmd));
			}
        };
		reader.write=function(data){
			if (!SocketOpen){ 
				alert("RFID讀寫服務未開啟,先下載服務並安裝!");
			}
			SendCmd(FUNCIDS._write, data);
		};
		reader.read=function(){
			if (!SocketOpen){ 
				alert("RFID讀寫服務未開啟,先下載服務並安裝!");
			}			
			SendCmd(FUNCIDS._read);
		};
        reader.getId=function(){
            if (!SocketOpen){ 
				alert("RFID讀寫服務未開啟,先下載服務並安裝!");
			}			
			SendCmd(FUNCIDS._getId);
        }

        return reader;
    }
};

function EventTarget()
{
    this.handlers = {};
}

EventTarget.prototype = {
    constructor: EventTarget,addEvent: function(type, handler){
        if(typeof this.handlers[type] == 'undefined'){this.handlers[type] = [];}this.handlers[type].push(handler);
    },fireEvent: function(event){
        if(!event.target){
            event.target = this;
        }
        if(this.handlers[event.type] instanceof Array){
            var handlers = this.handlers[event.type];for(var i = 0; i < handlers.length; i++){
                handlers[i](event);
            }
        }},removeEvent: function(type, handler){
        if(this.handlers[type] instanceof Array){
            var handlers = this.handlers[type];
            for(var i = 0; i < handlers.length; i++){
                if(handlers[i] == handler){break;}
            }
            handlers.splice(i, 1);
        }
    }
};

function _getCmdResult(relPara)
{
	var iRel;
	var separator = relPara.indexOf(",");
	if(separator != -1)
	{
		iRel = relPara.substr(0, separator);
	}
	else
		iRel = relPara.substr(0);	

	return iRel;
}
function _getResultPara(relPara)
{
	var szPara="";
	var separator = relPara.indexOf(",");
	if(separator != -1)
	{
		szPara = relPara.substr(separator+1);
	}
	return szPara;
}

try
{
 var embed_reader = SmartReader.OBJ();
}
catch(e)
{
}

if(!embed_reader.createSocket())
{
}

使用:

    <script type="text/javascript" charset="utf-8" src="/js/rwinterface.js?v=1"  charset="utf-8"></script>
        <script type="text/javascript">
          var rfid_obj = embed_reader.getOBJ();
           rfid_obj.onResult(function(rData){
                var result = rData.data;
                var cCaseCode = document.getElementById("cCaseCode");
	            switch(rData.functionId)
                {
                    case FUNCIDS._getId:
		                //讀取回調
		                if (result.result)
		                {
                             //var str = unescape(result.data.replace(/\u/g, "%u"));
			                //cCaseCode.value=str;  //把返回的
                            $.post("AjaxEdit.aspx",{"iOPType":2,"cID":result.errorMessage},function(data){
                                var res = data.split('|@|');
                                if (res[0] == "-1") {
                                    alert(res[1]);
                                    return;
                                }
                                else {
                                 //cCaseCode.value=res[1];
                                 getCaseInfo(res[1]);

                                }
                            },"");
                            setTimeout("ReadRFID()",100);
		                }
		                else {
                            alert("讀RFID出錯:" + result.errorMessage);
		                }
                    break;
	            }
                
            });

        //讀取RFID
        function ReadRFID(){
            rfid_obj.getId();
          
        }
        </script>
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM