狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C# 使用WebSocket創(chuàng)建聊天室案例

admin
2019年11月12日 17:50 本文熱度 3927
WebSocket介紹
WebSocket是HTML5開始提供的一種在單個 TCP 連接上進行全雙工通訊的協(xié)議。

在WebSocket API中,瀏覽器和服務(wù)器只需要做一個握手的動作,然后,瀏覽器和服務(wù)器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據(jù)互相傳送。

瀏覽器通過 JavaScript 向服務(wù)器發(fā)出建立 WebSocket 連接的請求,連接建立以后,客戶端和服務(wù)器端就可以通過 TCP 連接直接交換數(shù)據(jù)。

當(dāng)你獲取 Web Socket 連接后,你可以通過 send() 方法來向服務(wù)器發(fā)送數(shù)據(jù),并通過 onmessage 事件來接收服務(wù)器返回的數(shù)據(jù)。

其實WebSocket與Socket區(qū)別不大,只是客戶端是在瀏覽器上實現(xiàn)的,替代了傳統(tǒng)的輪詢機制,減少帶寬和資源

C#中WebSocket定義事件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    /// <summary>
    /// 聲明新連接處理事件
    /// </summary>
    /// <param name="loginName"></param>
    /// <param name="e"></param>
    public delegate void NewConnection_EventHandler(string loginName, EventArgs args);
 
    /// <summary>
    /// 聲明接收數(shù)據(jù)處理事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="message"></param>
    /// <param name="args"></param>
    public delegate void DataReceive_EventHandler(object sender, string message, EventArgs args);
 
    /// <summary>
    /// 聲明斷開連接處理事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    public delegate void Disconncetion_EventHandler(object sender, string message, EventArgs args);
}

WebSocket服務(wù)端實現(xiàn)代碼
WebSocketServer代碼

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    /// <summary>
    /// Socket服務(wù)端
    /// </summary>
    public class WebSocketServer : IDisposable
    {
        #region 私有變量
        /// <summary>
        /// ip
        /// </summary>
        private string _ip = string.Empty;
        /// <summary>
        /// 端口
        /// </summary>
        private int _port = 0;
        /// <summary>
        /// 服務(wù)器地址
        /// </summary>
        private string _serverLocation = string.Empty;
        /// <summary>
        /// Socket對象
        /// </summary>
        private Socket _socket = null;
        /// <summary>
        /// 監(jiān)聽的最大連接數(shù)
        /// </summary>
        private int maxListenConnect = 10;
        /// <summary>
        /// 是否關(guān)閉Socket對象
        /// </summary>
        private bool isDisposed = false;
 
        private Logger logger = null;
        /// <summary>
        /// buffer緩存區(qū)字節(jié)數(shù)
        /// </summary>
        private int maxBufferSize = 0;
        /// <summary>
        /// 第一個字節(jié),以0x00開始
        /// </summary>
        private byte[] FirstByte;
        /// <summary>
        /// 最后一個字節(jié),以0xFF結(jié)束
        /// </summary>
        private byte[] LastByte;
        #endregion
 
        #region 聲明Socket處理事件
        /// <summary>
        /// Socket新連接事件
        /// </summary>
        public event NewConnection_EventHandler NewConnectionHandler;
        /// <summary>
        /// Socket接收消息事件
        /// </summary>
        public event DataReceive_EventHandler DataReceiveHandler;
        /// <summary>
        /// Socket斷開連接事件
        /// </summary>
        public event Disconncetion_EventHandler DisconnectionHandler;
        #endregion
 
        /// <summary>
        /// 存放SocketConnection集合
        /// </summary>
        List<SocketConnection> SocketConnections = new List<SocketConnection>();
 
        #region 構(gòu)造函數(shù)
        public WebSocketServer()
        {
            this._ip = GetLocalMachineIPAddress().ToString();
            this._port = 9000;
            this._serverLocation = string.Format("ws://{0}:{1}", this._ip, this._port);
            Initialize();
        }
        public WebSocketServer(string ip, int port)
        {
            this._ip = ip;
            this._port = port;
            this._serverLocation = string.Format("ws://{0}:{1}", this._ip, this._port);
            Initialize();
        }
        public WebSocketServer(string ip, int port, string serverLocation)
        {
            this._ip = ip;
            this._port = port;
            this._serverLocation = serverLocation;
            Initialize();
        }
        #endregion
 
        /// <summary>
        /// 初始化私有變量
        /// </summary>
        private void Initialize()
        {
            isDisposed = false;
            logger = new Logger()
            {
                LogEvents = true
            };
            maxBufferSize = 1024 * 1024;
            maxListenConnect = 500;
            FirstByte = new byte[maxBufferSize];
            LastByte = new byte[maxBufferSize];
            FirstByte[0] = 0x00;
            LastByte[0] = 0xFF;
        }
 
        /// <summary>
        /// 開啟服務(wù)
        /// </summary>
        public void StartServer()
        {
            try
            {
                //實例化套接字
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //創(chuàng)建IP對象
                IPAddress address = GetLocalMachineIPAddress();
                //創(chuàng)建網(wǎng)絡(luò)端點,包括ip和port
                IPEndPoint endPoint = new IPEndPoint(address, _port);
                //將socket與本地端點綁定
                _socket.Bind(endPoint);
                //設(shè)置最大監(jiān)聽數(shù)
                _socket.Listen(maxListenConnect);
 
                logger.Log(string.Format("聊天服務(wù)器啟動。監(jiān)聽地址:{0}, 端口:{1}", this._ip, this._port));
                logger.Log(string.Format("WebSocket服務(wù)器地址: ws://{0}:{1}", this._ip, this._port));
 
                //開始監(jiān)聽客戶端
                Thread thread = new Thread(ListenClientConnect);
                thread.Start();
            }
            catch (Exception ex)
            {
                logger.Log(ex.Message);
            }
        }
 
        /// <summary>
        /// 監(jiān)聽客戶端連接
        /// </summary>
        private void ListenClientConnect()
        {
            try
            {
                while (true)
                {
                    //為新建連接創(chuàng)建的Socket
                    Socket socket = _socket.Accept();
                    if (socket != null)
                    {
                        //線程不休眠的話,會導(dǎo)致回調(diào)函數(shù)的AsyncState狀態(tài)出異常
                        Thread.Sleep(100);
                        SocketConnection socketConnection = new SocketConnection(this._ip, this._port, this._serverLocation)
                        {
                            ConnectionSocket = socket
                        };
                        //綁定事件
                        socketConnection.NewConnectionHandler += SocketConnection_NewConnectionHandler;
                        socketConnection.DataReceiveHandler += SocketConnection_DataReceiveHandler;
                        socketConnection.DisconnectionHandler += SocketConnection_DisconnectionHandler;
                        //從開始連接的Socket中異步接收消息
                        socketConnection.ConnectionSocket.BeginReceive(socketConnection.receivedDataBuffer,
                                        0, socketConnection.receivedDataBuffer.Length,
                                        0, new AsyncCallback(socketConnection.ManageHandshake),
                                        socketConnection.ConnectionSocket.Available);
                        //存入集合,以便在Socket發(fā)送消息時發(fā)送給所有連接的Socket套接字
                        SocketConnections.Add(socketConnection);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
 
        }
 
        /// <summary>
        /// SocketConnection監(jiān)聽的新連接事件
        /// </summary>
        /// <param name="loginName"></param>
        /// <param name="args"></param>
        private void SocketConnection_NewConnectionHandler(string loginName, EventArgs args)
        {
            NewConnectionHandler?.Invoke(loginName, EventArgs.Empty);
        }
        /// <summary>
        /// SocketConnection監(jiān)聽的消息接收事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="msgData"></param>
        /// <param name="args"></param>
        private void SocketConnection_DataReceiveHandler(object sender, string msgData, EventArgs args)
        {
            //新用戶連接進來時顯示歡迎信息
            //SocketConnection socketConnection = sender as SocketConnection;
            Send(msgData);
        }
        /// <summary>
        /// SocketConnection監(jiān)聽的斷開連接事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void SocketConnection_DisconnectionHandler(object sender, string message, EventArgs args)
        {
            if (sender is SocketConnection socket)
            {
                Send(message);
                socket.ConnectionSocket.Close();
                SocketConnections.Remove(socket);
            }
        }
 
        /// <summary>
        /// 發(fā)送消息
        /// </summary>
        /// <param name="message"></param>
        public void Send(string message)
        {
            //給所有連接上的發(fā)送消息
            foreach (SocketConnection socket in SocketConnections)
            {
                if (!socket.ConnectionSocket.Connected)
                {
                    continue;
                }
                try
                {
                    if (socket.IsDataMasked)
                    {
                        DataFrame dataFrame = new DataFrame(message);
                        socket.ConnectionSocket.Send(dataFrame.GetBytes());
                    }
                    else
                    {
                        socket.ConnectionSocket.Send(FirstByte);
                        socket.ConnectionSocket.Send(Encoding.UTF8.GetBytes(message));
                        socket.ConnectionSocket.Send(LastByte);
                    }
                }
                catch (Exception ex)
                {
                    logger.Log(ex.Message);
                }
            }
        }
 
        /// <summary>
        /// 獲取當(dāng)前主機的IP地址
        /// </summary>
        /// <returns></returns>
        private IPAddress GetLocalMachineIPAddress()
        {
            //獲取計算機主機名
            string hostName = Dns.GetHostName();
            //將主機名解析為IPHostEntry
            IPHostEntry hostEntry = Dns.GetHostEntry(hostName);
            foreach (IPAddress address in hostEntry.AddressList)
            {
                //IP4尋址協(xié)議
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    return address;
                }
            }
            return hostEntry.AddressList[0];
        }
 
        ~WebSocketServer()
        {
            Close();
        }
 
        public void Dispose()
        {
            Close();
        }
        public void Close()
        {
            if (!isDisposed)
            {
                isDisposed = true;
                if (_socket != null)
                {
                    _socket.Close();
                }
                foreach (SocketConnection socketConnection in SocketConnections)
                {
                    socketConnection.ConnectionSocket.Close();
                }
                SocketConnections.Clear();
                GC.SuppressFinalize(this);
            }
        }
    }
}

自定義的SocketConnection類

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    /// <summary>
    /// Socket成功建立的連接
    /// </summary>
    public class SocketConnection
    {
        /// <summary>
        /// 新的Socket連接
        /// </summary>
        public Socket ConnectionSocket = null;
 
        #region Socket監(jiān)聽事件
        /// <summary>
        /// 新連接事件
        /// </summary>
        public event NewConnection_EventHandler NewConnectionHandler;
        /// <summary>
        /// 數(shù)據(jù)接收事件
        /// </summary>
        public event DataReceive_EventHandler DataReceiveHandler;
        /// <summary>
        /// 斷開連接事件
        /// </summary>
        public event Disconncetion_EventHandler DisconnectionHandler;
        #endregion
 
        #region 私有變量
        private string _ip = string.Empty;
        private int _port = 0;
        private string _serverLocation = string.Empty;
 
        private Logger logger;
 
        private string loginId;
        public string LoginId
        {
            get => loginId; set => loginId = value;
        }
        private bool isDataMasked;
        public bool IsDataMasked { get => isDataMasked; set => isDataMasked = value; }
        /// <summary>
        /// 最大緩存區(qū)字節(jié)數(shù)
        /// </summary>
        private int maxBufferSize = 0;
        /// <summary>
        /// 握手協(xié)議信息
        /// </summary>
        private string handshake = string.Empty;
        /// <summary>
        /// 握手協(xié)議信息(new)
        /// </summary>
        private string newHandshake = string.Empty;
        /// <summary>
        /// 接收消息的數(shù)據(jù)緩存區(qū)
        /// </summary>
        public byte[] receivedDataBuffer;
        private byte[] firstByte;
        private byte[] lastByte;
        private byte[] serverKey1;
        private byte[] serverKey2;
        #endregion
 
        #region 構(gòu)造函數(shù)
        public SocketConnection()
        {
            Initialize();
        }
 
        public SocketConnection(string ip, int port, string serverLocation)
        {
            this._ip = ip;
            this._port = port;
            this._serverLocation = serverLocation;
            Initialize();
        }
        #endregion
 
        /// <summary>
        /// 初始化變量
        /// </summary>
        private void Initialize()
        {
            logger = new Logger();
            maxBufferSize = 1024 * 1024;
            receivedDataBuffer = new byte[maxBufferSize];
            firstByte = new byte[maxBufferSize];
            lastByte = new byte[maxBufferSize];
            firstByte[0] = 0x00;
            lastByte[0] = 0xFF;
 
            //webSocket攜帶頭信息
            handshake = "HTTP/1.1 101 Web Socket Protocol Handshake" + Environment.NewLine;
            handshake += "Upgrade: WebSocket" + Environment.NewLine;
            handshake += "Connection: Upgrade" + Environment.NewLine;
            handshake += "Sec-WebSocket-Origin: " + "{0}" + Environment.NewLine;
            handshake += string.Format("Sec-WebSocket-Location: " + "ws://{0}:{1}" + Environment.NewLine, this._ip, this._port);
            handshake += Environment.NewLine;
 
            newHandshake = "HTTP/1.1 101 Switching Protocols" + Environment.NewLine;
            newHandshake += "Upgrade: WebSocket" + Environment.NewLine;
            newHandshake += "Connection: Upgrade" + Environment.NewLine;
            newHandshake += "Sec-WebSocket-Accept: {0}" + Environment.NewLine;
            newHandshake += Environment.NewLine;
        }
 
        /// <summary>
        /// 處理異步接收消息回調(diào)方法
        /// </summary>
        /// <param name="asyncResult"></param>
        public void ManageHandshake(IAsyncResult asyncResult)
        {
            try
            {
                string header = "Sec-WebSocket-Version:";
                int HandshakeLength = (int)asyncResult.AsyncState;
                byte[] last8Bytes = new byte[8];
 
                UTF8Encoding encoding = new UTF8Encoding();
                String rawClientHandshake = encoding.GetString(receivedDataBuffer, 0, HandshakeLength);
 
                Array.Copy(receivedDataBuffer, HandshakeLength - 8, last8Bytes, 0, 8);
                //現(xiàn)在使用的是比較新的WebSocket協(xié)議
                if (rawClientHandshake.IndexOf(header) != -1)
                {
                    this.isDataMasked = true;
                    string[] rawClientHandshakeLines = rawClientHandshake.Split(new string[] { Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries);
 
                    string acceptKey = "";
                    foreach (string line in rawClientHandshakeLines)
                    {
                        if (line.Contains("Sec-WebSocket-Key:"))
                        {
                            acceptKey = ComputeWebSocketHandshakeSecurityHash09(line.Substring(line.IndexOf(":") + 2));
                        }
                    }
                    newHandshake = string.Format(newHandshake, acceptKey);
                    byte[] newHandshakeText = Encoding.UTF8.GetBytes(newHandshake);
                    //將數(shù)據(jù)異步發(fā)送到連接的socket上
                    ConnectionSocket.BeginSend(newHandshakeText, 0, newHandshakeText.Length, SocketFlags.None, HandshakeFinished, null);
                    return;
                }
 
                string clientHandshake = encoding.GetString(receivedDataBuffer, 0, receivedDataBuffer.Length - 8);
                string[] clientHandshakeLines = clientHandshake.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
 
                logger.Log("新的連接請求來自:" + ConnectionSocket.LocalEndPoint + ".正準(zhǔn)備進行連接...");
 
                // Welcome the new client
                foreach (string Line in clientHandshakeLines)
                {
                    logger.Log(Line);
                    if (Line.Contains("Sec-WebSocket-Key1:"))
                        BuildServerPartialKey(1, Line.Substring(Line.IndexOf(":") + 2));
                    if (Line.Contains("Sec-WebSocket-Key2:"))
                        BuildServerPartialKey(2, Line.Substring(Line.IndexOf(":") + 2));
                    if (Line.Contains("Origin:"))
                        try
                        {
                            handshake = string.Format(handshake, Line.Substring(Line.IndexOf(":") + 2));
                        }
                        catch
                        {
                            handshake = string.Format(handshake, "null");
                        }
                }
                //為客戶端建立響應(yīng)
                byte[] handshakeText = Encoding.UTF8.GetBytes(handshake);
                byte[] serverHandshakeResponse = new byte[handshakeText.Length + 16];
                byte[] serverKey = BuildServerFullKey(last8Bytes);
                Array.Copy(handshakeText, serverHandshakeResponse, handshakeText.Length);
                Array.Copy(serverKey, 0, serverHandshakeResponse, handshakeText.Length, 16);
 
                logger.Log("發(fā)送握手信息 ...");
                ConnectionSocket.BeginSend(serverHandshakeResponse, 0, handshakeText.Length + 16, 0, HandshakeFinished, null);
                logger.Log(handshake);
 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
 
        /// <summary>
        /// 由服務(wù)端像客戶端發(fā)送消息完成回調(diào)
        /// </summary>
        /// <param name="asyncResult"></param>
        private void HandshakeFinished(IAsyncResult asyncResult)
        {
            //結(jié)束掛起的異步發(fā)送
            ConnectionSocket.EndSend(asyncResult);
            ConnectionSocket.BeginReceive(receivedDataBuffer, 0, receivedDataBuffer.Length,
                0, new AsyncCallback(Read), null);
            NewConnectionHandler?.Invoke("", EventArgs.Empty);
        }
 
        private void Read(IAsyncResult asyncResult)
        {
            if (!ConnectionSocket.Connected)
            {
                return;
            }
            string message = string.Empty;
            DataFrame dataFrame = new DataFrame(receivedDataBuffer);
            try
            {
                if (!this.isDataMasked)
                {
                    //WebSocket協(xié)議:消息以0x00和0xFF作為填充字節(jié)發(fā)送
                    UTF8Encoding encoding = new UTF8Encoding();
                    int startIndex = 0;
                    int endIndex = 0;
 
                    // Search for the start byte
                    while (receivedDataBuffer[startIndex] == firstByte[0])
                    {
                        startIndex++;
                    }
                    // Search for the end byte
                    endIndex = startIndex + 1;
                    while (receivedDataBuffer[endIndex] != lastByte[0] && endIndex != maxBufferSize - 1)
                    {
                        endIndex++;
                    }
                    if (endIndex == maxBufferSize - 1)
                    {
                        endIndex = maxBufferSize;
                    }
                    // Get the message
                    message = encoding.GetString(receivedDataBuffer, startIndex, endIndex - startIndex);
                }//if
                else
                {
                    message = dataFrame.Text;
                }
 
                if ((message.Length == maxBufferSize && message[0] == Convert.ToChar(65533)) ||
                      message.Length == 0)
                {
                    //斷開連接
                    logger.Log("message");
                    if (string.IsNullOrEmpty(message))
                    {
                        MessageInfo messageInfo = new MessageInfo()
                        {
                            MsgType = MessageType.None,
                            Message = ""
                        };
                        message = JsonConvert.SerializeObject(messageInfo);
                    }
                    DisconnectionHandler?.Invoke(this, message, EventArgs.Empty);
                }
                else
                {
                    if (DataReceiveHandler != null)
                    {
                        logger.Log("接受到的信息 [\"" + message + "\"]");
                        //消息發(fā)送
                        DataReceiveHandler(this, message, EventArgs.Empty);
                    }
                    Array.Clear(receivedDataBuffer, 0, receivedDataBuffer.Length);
                    ConnectionSocket.BeginReceive(receivedDataBuffer, 0, receivedDataBuffer.Length, 0, Read, null);
                }
            }
            catch (Exception ex)
            {
                logger.Log(ex.Message);
                logger.Log("Socket連接將會被終止.");
                MessageInfo messageInfo = new MessageInfo()
                {
                    MsgType = MessageType.Error,
                    Message = ex.Message + Environment.NewLine + "Socket連接將會被終止"
                };
                DisconnectionHandler?.Invoke(this, JsonConvert.SerializeObject(messageInfo), EventArgs.Empty);
            }
        }
 
        private byte[] BuildServerFullKey(byte[] last8Bytes)
        {
            byte[] concatenatedKeys = new byte[16];
            Array.Copy(serverKey1, 0, concatenatedKeys, 0, 4);
            Array.Copy(serverKey2, 0, concatenatedKeys, 4, 4);
            Array.Copy(last8Bytes, 0, concatenatedKeys, 8, 8);
 
            // MD5 Hash
            MD5 MD5Service = MD5.Create();
            return MD5Service.ComputeHash(concatenatedKeys);
        }
 
        private void BuildServerPartialKey(int keyNum, string clientKey)
        {
            string partialServerKey = "";
            byte[] currentKey;
            int spacesNum = 0;
            char[] keyChars = clientKey.ToCharArray();
            foreach (char currentChar in keyChars)
            {
                if (char.IsDigit(currentChar)) partialServerKey += currentChar;
                if (char.IsWhiteSpace(currentChar)) spacesNum++;
            }
            try
            {
                currentKey = BitConverter.GetBytes((int)(Int64.Parse(partialServerKey) / spacesNum));
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(currentKey);
                }
 
                if (keyNum == 1)
                {
                    serverKey1 = currentKey;
                }
                else
                {
                    serverKey2 = currentKey;
                }
            }
            catch
            {
                if (serverKey1 != null)
                {
                    Array.Clear(serverKey1, 0, serverKey1.Length);
                }
                if (serverKey2 != null)
                {
                    Array.Clear(serverKey2, 0, serverKey2.Length);
                }
            }
        }
 
        private string ComputeWebSocketHandshakeSecurityHash09(string secWebSocketKey)
        {
            const String MagicKEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
            String secWebSocketAccept = String.Empty;
            // 1. Combine the request Sec-WebSocket-Key with magic key.
            String ret = secWebSocketKey + MagicKEY;
            // 2. Compute the SHA1 hash
            SHA1 sha = new SHA1CryptoServiceProvider();
            byte[] sha1Hash = sha.ComputeHash(Encoding.UTF8.GetBytes(ret));
            // 3. Base64 encode the hash
            secWebSocketAccept = Convert.ToBase64String(sha1Hash);
            return secWebSocketAccept;
        }
    }
}

數(shù)據(jù)文件相關(guān)的類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    public class DataFrame
    {
        DataFrameHeader _header;
        private byte[] _extend = new byte[0];
        private byte[] _mask = new byte[0];
        private byte[] _content = new byte[0];
 
        public DataFrame(byte[] buffer)
        {
            //幀頭
            _header = new DataFrameHeader(buffer);
 
            //擴展長度
            if (_header.Length == 126)
            {
                _extend = new byte[2];
                Buffer.BlockCopy(buffer, 2, _extend, 0, 2);
            }
            else if (_header.Length == 127)
            {
                _extend = new byte[8];
                Buffer.BlockCopy(buffer, 2, _extend, 0, 8);
            }
 
            //是否有掩碼
            if (_header.HasMask)
            {
                _mask = new byte[4];
                Buffer.BlockCopy(buffer, _extend.Length + 2, _mask, 0, 4);
            }
 
            //消息體
            if (_extend.Length == 0)
            {
                _content = new byte[_header.Length];
                Buffer.BlockCopy(buffer, _extend.Length + _mask.Length + 2, _content, 0, _content.Length);
            }
            else if (_extend.Length == 2)
            {
                int contentLength = (int)_extend[0] * 256 + (int)_extend[1];
                _content = new byte[contentLength];
                Buffer.BlockCopy(buffer, _extend.Length + _mask.Length + 2, _content, 0, contentLength > 1024 * 100 ? 1024 * 100 : contentLength);
            }
            else
            {
                long len = 0;
                int n = 1;
                for (int i = 7; i >= 0; i--)
                {
                    len += (int)_extend[i] * n;
                    n *= 256;
                }
                _content = new byte[len];
                Buffer.BlockCopy(buffer, _extend.Length + _mask.Length + 2, _content, 0, _content.Length);
            }
 
            if (_header.HasMask) _content = Mask(_content, _mask);
 
        }
 
        public DataFrame(string content)
        {
            _content = Encoding.UTF8.GetBytes(content);
            int length = _content.Length;
 
            if (length < 126)
            {
                _extend = new byte[0];
                _header = new DataFrameHeader(true, false, false, false, 1, false, length);
            }
            else if (length < 65536)
            {
                _extend = new byte[2];
                _header = new DataFrameHeader(true, false, false, false, 1, false, 126);
                _extend[0] = (byte)(length / 256);
                _extend[1] = (byte)(length % 256);
            }
            else
            {
                _extend = new byte[8];
                _header = new DataFrameHeader(true, false, false, false, 1, false, 127);
 
                int left = length;
                int unit = 256;
 
                for (int i = 7; i > 1; i--)
                {
                    _extend[i] = (byte)(left % unit);
                    left = left / unit;
 
                    if (left == 0)
                        break;
                }
            }
        }
 
        public byte[] GetBytes()
        {
            byte[] buffer = new byte[2 + _extend.Length + _mask.Length + _content.Length];
            Buffer.BlockCopy(_header.GetBytes(), 0, buffer, 0, 2);
            Buffer.BlockCopy(_extend, 0, buffer, 2, _extend.Length);
            Buffer.BlockCopy(_mask, 0, buffer, 2 + _extend.Length, _mask.Length);
            Buffer.BlockCopy(_content, 0, buffer, 2 + _extend.Length + _mask.Length, _content.Length);
            return buffer;
        }
 
        public string Text
        {
            get
            {
                if (_header.OpCode != 1)
                    return string.Empty;
 
                return Encoding.UTF8.GetString(_content);
            }
        }
 
        private byte[] Mask(byte[] data, byte[] mask)
        {
            for (var i = 0; i < data.Length; i++)
            {
                data[i] = (byte)(data[i] ^ mask[i % 4]);
            }
 
            return data;
        }
 
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    public class DataFrameHeader
    {
        private bool _fin;
        private bool _rsv1;
        private bool _rsv2;
        private bool _rsv3;
        private sbyte _opcode;
        private bool _maskcode;
        private sbyte _payloadlength;
 
        public bool FIN { get { return _fin; } }
 
        public bool RSV1 { get { return _rsv1; } }
 
        public bool RSV2 { get { return _rsv2; } }
 
        public bool RSV3 { get { return _rsv3; } }
 
        public sbyte OpCode { get { return _opcode; } }
 
        public bool HasMask { get { return _maskcode; } }
 
        public sbyte Length { get { return _payloadlength; } }
 
        public DataFrameHeader(byte[] buffer)
        {
            if (buffer.Length < 2)
                throw new Exception("無效的數(shù)據(jù)頭.");
 
            //第一個字節(jié)
            _fin = (buffer[0] & 0x80) == 0x80;
            _rsv1 = (buffer[0] & 0x40) == 0x40;
            _rsv2 = (buffer[0] & 0x20) == 0x20;
            _rsv3 = (buffer[0] & 0x10) == 0x10;
            _opcode = (sbyte)(buffer[0] & 0x0f);
 
            //第二個字節(jié)
            _maskcode = (buffer[1] & 0x80) == 0x80;
            _payloadlength = (sbyte)(buffer[1] & 0x7f);
 
        }
 
        //發(fā)送封裝數(shù)據(jù)
        public DataFrameHeader(bool fin, bool rsv1, bool rsv2, bool rsv3, sbyte opcode, bool hasmask, int length)
        {
            _fin = fin;
            _rsv1 = rsv1;
            _rsv2 = rsv2;
            _rsv3 = rsv3;
            _opcode = opcode;
            //第二個字節(jié)
            _maskcode = hasmask;
            _payloadlength = (sbyte)length;
        }
 
        //返回幀頭字節(jié)
        public byte[] GetBytes()
        {
            byte[] buffer = new byte[2] { 0, 0 };
 
            if (_fin) buffer[0] ^= 0x80;
            if (_rsv1) buffer[0] ^= 0x40;
            if (_rsv2) buffer[0] ^= 0x20;
            if (_rsv3) buffer[0] ^= 0x10;
 
            buffer[0] ^= (byte)_opcode;
 
            if (_maskcode) buffer[1] ^= 0x80;
 
            buffer[1] ^= (byte)_payloadlength;
 
            return buffer;
        }
    }
}

自定義的枚舉,實體,封裝客戶端輸出類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    public enum MessageType
    {
        Error = -1,
        None = 0,
        /// <summary>
        /// 登錄
        /// </summary>
        Login = 1,
        /// <summary>
        /// 退出
        /// </summary>
        Logout = 2,
        /// <summary>
        /// 聊天消息
        /// </summary>
        ChatInfo = 3,
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    public class MessageInfo
    {
        /// <summary>
        /// 唯一標(biāo)識
        /// </summary>
        public Guid Identity { get; set; }
        /// <summary>
        /// 用戶名
        /// </summary>
        public string UserName { get; set; }
        /// <summary>
        /// 消息類型
        /// </summary>
        public MessageType MsgType { get; set; }
        /// <summary>
        /// 發(fā)送信息
        /// </summary>
        public string Message { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WebSocketsServer
{
    public class Logger
    {
        public bool LogEvents { get; set; }
        public Logger()
        {
            LogEvents = true;
        }
 
        public void Log(string Text)
        {
            if (LogEvents) Console.WriteLine(Text);
        }
    }
}

Program類的實現(xiàn)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
/// <summary>
/// WebSocket服務(wù)端
/// </summary>
namespace WebSocketsServer
{
    class Program
    {
        static void Main(string[] args)
        {
            WebSocketServer server = new WebSocketServer();
            server.StartServer();
            Console.ReadKey();
        }
    }
}

HTML頁面實現(xiàn)代碼如下(客戶端)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>WebSocket聊天室</title>
    <style type="text/css">
        .container {
            font-family: "Courier New";
            width: 500px;
            height: 400px;
            overflow: auto;
            border: 1px solid black;
            padding: 8px;
            background-color: lightgray;
        }
 
        .LockOff {
            display: none;
            visibility: hidden;
        }
 
        .LockOn {
            display: block;
            visibility: visible;
            position: absolute;
            z-index: 999;
            top: 0px;
            left: 0px;
            width: 1024%;
            height: 768%;
            background-color: #ccc;
            text-align: center;
            padding-top: 20%;
            filter: alpha(opacity=75);
            opacity: 0.75;
        }
 
        .userName {
            color: white;
           
        }
 
        .chatLeft {
            display: inline-block;
            color: black;
           
            margin-left: 20px;
            padding: 3px;
            border: 1px solid #ccc;
            background-color: #fff;
            text-align: left;
            vertical-align: middle;
        }
 
        .chatRight {
            display: inline-block;
            color: white;
           
            padding: 3px;
            border: 1px solid #ccc;
            background-color: #9eea6a;
            text-align: left;
            vertical-align: middle;
        }
 
        .login {
            width: 100%;
            display: inline-block;
            text-align: center;
            color: #ffff33;
           
            font-weight: 700;
        }
 
        .logout {
            width: 100%;
            display: inline-block;
            text-align: center;
            color: #ffa31a;
           
        }
 
        .systemInfo {
            color: gray;
            font-size: 15px;
        }
 
        .error {
            width: 100%;
            display: inline-block;
            text-align: center;
            color: red;
            font-size: 16px;
            font-weight: 700;
        }
    </style>
</head>
<body>
    <div id="skm_LockPane" class="LockOff"></div>
    <form id="form1" runat="server">
        <h1>WebSocket 聊天室</h1>
        <div>
            按下連接按鈕,會通過WebSocket發(fā)起一個到聊天瀏覽器的連接。
        </div>
        服務(wù)器地址: <input type="text" id="Connection" /> 用戶名: <input type="text" id="txtName" value="陳先生" />
        <button id=''ToggleConnection'' type="button" οnclick=''ToggleConnectionClicked();''>連接</button>
        <input type="hidden" value="" id="identity" />
        <br />
        <br />
        <div id=''LogContainer'' class=''container''>
        </div>
        <br />
        <div id=''SendDataContainer''>
            <input type="text" id="DataToSend" size="68" />
            <button id=''SendData'' type="button" οnclick=''SendDataClicked();''>發(fā)送</button>
        </div>
        <br />
    </form>
 
    <script src="Scripts/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        //webSocket對象
        var ws;
        //Socket是否創(chuàng)建
        var SocketCreated = false;
        //用戶是否退出登錄
        var isUserloggedout = false;
 
        //模擬用戶唯一標(biāo)識
        var identity = "";
        var userName = "";
        var LOGIN = 1, LOGOUT = 2, CHATINFO = 3, SYSYEMINFO = 4, ERROR = -1;
 
        function lockOn(str) {
            var lock = document.getElementById(''skm_LockPane'');
            if (lock)
                lock.className = ''LockOn'';
            lock.innerHTML = str;
        }
 
        function lockOff() {
            var lock = document.getElementById(''skm_LockPane'');
            lock.className = ''LockOff'';
        }
 
        function ToggleConnectionClicked() {
            userName = document.getElementById("txtName").value.trim();
            if (identity.trim() == "") {
                identity = newGuid();
            }
            //(連接尚未建立||連接已建立)
            if (SocketCreated && (ws.readyState == 0 || ws.readyState == 1)) {
                lockOn("離開聊天室...");
                SocketCreated = false;
                isUserloggedout = true;
                var data = MsgData(LOGOUT, "【" + userName + "】" + "離開了聊天室!");
                ws.send(JSON.stringify(data));
                ws.close();
            } else {
                lockOn("進入聊天室...");
                var data = MsgData(SYSYEMINFO, "準(zhǔn)備連接到聊天服務(wù)器...");
                Log(data);
                try {
                    if ("WebSocket" in window) {
                        ws = new WebSocket("ws://" + document.getElementById("Connection").value);
                    }
                    else if ("MozWebSocket" in window) {
                        ws = new MozWebSocket("ws://" + document.getElementById("Connection").value);
                    }
                    SocketCreated = true;
                    isUserloggedout = false;
                } catch (ex) {
                    var data = MsgData(ERROR, ex);
                    Log(data);
                    return;
                }
                document.getElementById("ToggleConnection").innerHTML = "斷開";
                ws.onopen = WSonOpen;
                ws.onmessage = WSonMessage;
                ws.onclose = WSonClose;
                ws.onerror = WSonError;
            }
        };
 
        //WebSocket打開事件
        function WSonOpen() {
            lockOff();
            var data = MsgData(SYSYEMINFO, "連接已經(jīng)建立.");
            Log(data);
            $("#SendDataContainer").show();
            var data = MsgData(LOGIN, "歡迎【" + userName + "】來到聊天室!");
            ws.send(JSON.stringify(data));
        };
        //WebSocket接收消息事件
        function WSonMessage(event) {
            Log(event.data);
        };
        //WebSocket關(guān)閉連接事件
        function WSonClose() {
            lockOff();
            if (isUserloggedout) {
                var data = MsgData(LOGOUT, "【" + userName + "】" + "離開了聊天室!");
                Log(JSON.stringify(data));
            }
            document.getElementById("ToggleConnection").innerHTML = "連接";
            $("#SendDataContainer").hide();
        };
        //WebSocket發(fā)生錯誤
        function WSonError() {
            lockOff();
            var data = MsgData(ERROR, "遠程連接中斷...");
            Log(data);
        };
 
 
        function SendDataClicked() {
            if (document.getElementById("DataToSend").value.trim() != "") {
                var data = MsgData(CHATINFO, document.getElementById("DataToSend").value)
                ws.send(JSON.stringify(data));
                document.getElementById("DataToSend").value = "";
            }
        };
 
        //傳遞的消息對象
        function MsgData(MsgType, Message) {
            var data = new Object();
            data.Identity = identity;
            data.UserName = userName;
            data.MsgType = MsgType;
            data.Message = Message;
            return data;
        }
 
        function Log(data) {
            console.log(data);
            if (!(data.constructor === Object)) {
                data = JSON.parse(data);
            }
            var html = "";
            if (data.MsgType === CHATINFO) {
                if (data.Identity === identity) {
                    html = "<div style=''display:inline-block;width:100%;text-align:right;margin-bottom:2px''>";
                    html += "<span class=''chatRight''>" + data.Message + "</span>";
                    html += "</div>";
                }
                else {
                    html += "<span class=''userName''>" + data.UserName + ":</span>";
                    html += "</br>";
                    html += "<span class=''chatLeft''>" + data.Message + "</span>";
                }
            }
            else if (data.MsgType === LOGIN) {
                html = "<span class=''login''>" + data.Message + "</span>"
            }
            else if (data.MsgType === LOGOUT) {
                html = "<span class=''logout''>" + data.Message + "</span>"
            }
            else if (data.MsgType === SYSYEMINFO) {
                html += "<span class=''systemInfo''>" + data.Message + "</span>";
            }
            else if (data.MsgType === ERROR) {
                html = "<span class=''error''>" + data + "</span>";
            }
            document.getElementById("LogContainer").innerHTML = document.getElementById("LogContainer").innerHTML + html + "<br />";
            var LogContainer = document.getElementById("LogContainer");
            LogContainer.scrollTop = LogContainer.scrollHeight;
        };
        //JS生成GUID函數(shù),類似.net中的NewID();
        function newGuid() {
            var guid = "";
            for (var i = 1; i <= 32; i++) {
                var n = Math.floor(Math.random() * 16.0).toString(16);
                guid += n;
                if ((i == 8) || (i == 12) || (i == 16) || (i == 20))
                    guid += "-";
            }
            return guid;
        }
 
        $(document).ready(function () {
            $("#SendDataContainer").hide();
            var WebSocketsExist = false;
            if ("WebSocket" in window) {
                WebSocketsExist = true;
            }
            if (WebSocketsExist) {
                var data = MsgData(SYSYEMINFO, "您的瀏覽器支持WebSocket. 您可以嘗試連接到聊天服務(wù)器!");
                Log(data);
                document.getElementById("Connection").value = "192.168.137.1:9000";
            } else {
                var data = MsgData(ERROR, "您的瀏覽器不支持WebSocket。請選擇其他的瀏覽器再嘗試連接服務(wù)器。");
                Log(data);
                document.getElementById("ToggleConnection").disabled = true;
            }
 
            $("#DataToSend").keypress(function (evt) {
                if (evt.keyCode == 13) {
                    $("#SendData").click();
                    evt.preventDefault();
                }
            })
        });
 
    </script>
</body>
</html>

實現(xiàn)效果如圖(打開兩個HTML實現(xiàn)聊天功能)


控制臺獲取的信息如下:


完結(jié):
挺有趣的事情,希望熬夜不猝死了,哈哈。

該文章在 2019/11/12 17:50:07 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務(wù)費用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務(wù)都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved