• HTML5学习之WebSocket通讯(六)


    WebSocket是下一代客户端-服务器的异步通信方法.
    WebSocket最伟大之处在于服务器和客户端可以在任意时刻相互推送信息
    WebSocket允许跨域通信
    Ajax技术需要客户端发起请求,WebSocket服务器和客户端可以彼此相互推送信息
     
    下面实现一个简单的实时多人聊天系统
    WebSocket服务端:
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace WebSocketServer
    {
        class Program
        {
            static void Main(string[] args)
            {
                WebSocketServerTest WSServerTest = new WebSocketServerTest();
                WSServerTest.Start();
            }
        }
    
        public class WebSocketServerTest : IDisposable
        {
            private WebSocketServer WSServer;
            public WebSocketServerTest()
            {
                //使用默认的设置
                WSServer = new WebSocketServer();
            }
    
            public void Dispose()
            {
                Close();
            }
    
            private void Close()
            {
                WSServer.Dispose();
                GC.SuppressFinalize(this);
            }
    
            ~WebSocketServerTest()
            {
                Close();
            }
    
            public void Start()
            {
                WSServer.NewConnection += new NewConnectionEventHandler(WSServer_NewConnection);
                WSServer.Disconnected += new DisconnectedEventHandler(WSServer_Disconnected);
                WSServer.StartServer();
            }
    
            void WSServer_Disconnected(Object sender, EventArgs e)
            {
            }
    
            void WSServer_NewConnection(string loginName, EventArgs e)
            {
            }
        }
    
        public class Logger
        {
            public bool LogEvents { get; set; }
    
            public Logger()
            {
                LogEvents = true;
            }
    
            public void Log(string Text)
            {
                if (LogEvents) Console.WriteLine(Text);
            }
        }
    
        public enum ServerStatusLevel { Off, WaitingConnection, ConnectionEstablished };
    
        public delegate void NewConnectionEventHandler(string loginName, EventArgs e);
        public delegate void DataReceivedEventHandler(Object sender, string message, EventArgs e);
        public delegate void DisconnectedEventHandler(Object sender, EventArgs e);
        public delegate void BroadcastEventHandler(string message, EventArgs e);
    
        public class WebSocketServer : IDisposable
        {
            private bool AlreadyDisposed;
            private Socket Listener;
            private int ConnectionsQueueLength;
            private int MaxBufferSize;
            private string Handshake;
            private StreamReader ConnectionReader;
            private StreamWriter ConnectionWriter;
            private Logger logger;
            private byte[] FirstByte;
            private byte[] LastByte;
            private byte[] ServerKey1;
            private byte[] ServerKey2;
    
            List<SocketConnection> connectionSocketList = new List<SocketConnection>();
    
            public ServerStatusLevel Status { get; private set; }
            public int ServerPort { get; set; }
            public string ServerLocation { get; set; }
            public string ConnectionOrigin { get; set; }
            public bool LogEvents
            {
                get { return logger.LogEvents; }
                set { logger.LogEvents = value; }
            }
    
            public event NewConnectionEventHandler NewConnection;
            public event DataReceivedEventHandler DataReceived;
            public event DisconnectedEventHandler Disconnected;
    
            private void Initialize()
            {
                AlreadyDisposed = false;
                logger = new Logger();
    
                Status = ServerStatusLevel.Off;
                ConnectionsQueueLength = 500;
                MaxBufferSize = 1024 * 100;
                FirstByte = new byte[MaxBufferSize];
                LastByte = new byte[MaxBufferSize];
                FirstByte[0] = 0x00;
                LastByte[0] = 0xFF;
                logger.LogEvents = true;
            }
    
            public WebSocketServer()
            {
                ServerPort = 4141;
                ServerLocation = string.Format("ws://{0}:4141/chat", getLocalmachineIPAddress());
                Initialize();
            }
    
            public WebSocketServer(int serverPort, string serverLocation, string connectionOrigin)
            {
                ServerPort = serverPort;
                ConnectionOrigin = connectionOrigin;
                ServerLocation = serverLocation;
                Initialize();
            }
    
    
            ~WebSocketServer()
            {
                Close();
            }
    
    
            public void Dispose()
            {
                Close();
            }
    
            private void Close()
            {
                if (!AlreadyDisposed)
                {
                    AlreadyDisposed = true;
                    if (Listener != null) Listener.Close();
                    foreach (SocketConnection item in connectionSocketList)
                    {
                        item.ConnectionSocket.Close();
                    }
                    connectionSocketList.Clear();
                    GC.SuppressFinalize(this);
                }
            }
    
            public static IPAddress getLocalmachineIPAddress()
            {
                string strHostName = Dns.GetHostName();
                IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
    
                foreach (IPAddress ip in ipEntry.AddressList)
                {
                    //IPV4
                    if (ip.AddressFamily == AddressFamily.InterNetwork)
                        return ip;
                }
    
                return ipEntry.AddressList[0];
            }
    
            public void StartServer()
            {
                Char char1 = Convert.ToChar(65533);
    
                Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
                Listener.Bind(new IPEndPoint(getLocalmachineIPAddress(), ServerPort));
    
                Listener.Listen(ConnectionsQueueLength);
    
                logger.Log(string.Format("聊天服务器启动。监听地址:{0}, 端口:{1}", getLocalmachineIPAddress(), ServerPort));
                logger.Log(string.Format("WebSocket服务器地址: ws://{0}:{1}/chat", getLocalmachineIPAddress(), ServerPort));
    
                while (true)
                {
                    Socket sc = Listener.Accept();
    
                    if (sc != null)
                    {
                        System.Threading.Thread.Sleep(100);
                        SocketConnection socketConn = new SocketConnection();
                        socketConn.ConnectionSocket = sc;
                        socketConn.NewConnection += new NewConnectionEventHandler(socketConn_NewConnection);
                        socketConn.DataReceived += new DataReceivedEventHandler(socketConn_BroadcastMessage);
                        socketConn.Disconnected += new DisconnectedEventHandler(socketConn_Disconnected);
    
                        socketConn.ConnectionSocket.BeginReceive(socketConn.receivedDataBuffer,
                                                                 0, socketConn.receivedDataBuffer.Length,
                                                                 0, new AsyncCallback(socketConn.ManageHandshake),
                                                                 socketConn.ConnectionSocket.Available);
                        connectionSocketList.Add(socketConn);
                    }
                }
            }
    
            void socketConn_Disconnected(Object sender, EventArgs e)
            {
                SocketConnection sConn = sender as SocketConnection;
                if (sConn != null)
                {
                    Send(string.Format("【{0}】离开了聊天室!", sConn.Name));
                    sConn.ConnectionSocket.Close();
                    connectionSocketList.Remove(sConn);
                }
            }
    
            void socketConn_BroadcastMessage(Object sender, string message, EventArgs e)
            {
                if (message.IndexOf("login:") != -1)
                {
                    SocketConnection sConn = sender as SocketConnection;
                    sConn.Name = message.Substring(message.IndexOf("login:") + "login:".Length);
                    message = string.Format("欢迎【{0}】来到聊天室!", message.Substring(message.IndexOf("login:") + "login:".Length));
                }
                Send(message);
            }
    
            void socketConn_NewConnection(string name, EventArgs e)
            {
                if (NewConnection != null)
                    NewConnection(name, EventArgs.Empty);
            }
    
            public void Send(string message)
            {
                foreach (SocketConnection item in connectionSocketList)
                {
                    if (!item.ConnectionSocket.Connected) return;
                    try
                    {
                        if (item.IsDataMasked)
                        {
                            DataFrame dr = new DataFrame(message);
                            item.ConnectionSocket.Send(dr.GetBytes());
                        }
                        else
                        {
                            item.ConnectionSocket.Send(FirstByte);
                            item.ConnectionSocket.Send(Encoding.UTF8.GetBytes(message));
                            item.ConnectionSocket.Send(LastByte);
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.Log(ex.Message);
                    }
                }
            }
        }
    
        public class SocketConnection
        {
            private Logger logger;
    
            private string name;
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
    
            private Boolean isDataMasked;
            public Boolean IsDataMasked
            {
                get { return isDataMasked; }
                set { isDataMasked = value; }
            }
    
            public Socket ConnectionSocket;
    
            private int MaxBufferSize;
            private string Handshake;
            private string New_Handshake;
    
            public byte[] receivedDataBuffer;
            private byte[] FirstByte;
            private byte[] LastByte;
            private byte[] ServerKey1;
            private byte[] ServerKey2;
    
    
            public event NewConnectionEventHandler NewConnection;
            public event DataReceivedEventHandler DataReceived;
            public event DisconnectedEventHandler Disconnected;
    
            public SocketConnection()
            {
                logger = new Logger();
                MaxBufferSize = 1024 * 100;
                receivedDataBuffer = new byte[MaxBufferSize];
                FirstByte = new byte[MaxBufferSize];
                LastByte = new byte[MaxBufferSize];
                FirstByte[0] = 0x00;
                LastByte[0] = 0xFF;
    
                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}:4141/chat" + Environment.NewLine, WebSocketServer.getLocalmachineIPAddress());
                Handshake += Environment.NewLine;
    
                New_Handshake = "HTTP/1.1 101 Switching Protocols" + Environment.NewLine;
                New_Handshake += "Upgrade: WebSocket" + Environment.NewLine;
                New_Handshake += "Connection: Upgrade" + Environment.NewLine;
                New_Handshake += "Sec-WebSocket-Accept: {0}" + Environment.NewLine;
                New_Handshake += Environment.NewLine;
            }
    
            private void Read(IAsyncResult status)
            {
                if (!ConnectionSocket.Connected) return;
                string messageReceived = string.Empty;
                DataFrame dr = new DataFrame(receivedDataBuffer);
    
                try
                {
                    if (!this.isDataMasked)
                    {
                        // Web Socket protocol: messages are sent with 0x00 and 0xFF as padding bytes
                        System.Text.UTF8Encoding decoder = new System.Text.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
                        messageReceived = decoder.GetString(receivedDataBuffer, startIndex, endIndex - startIndex);
                    }
                    else
                    {
                        messageReceived = dr.Text;
                    }
    
                    if ((messageReceived.Length == MaxBufferSize && messageReceived[0] == Convert.ToChar(65533)) ||
                        messageReceived.Length == 0)
                    {
                        logger.Log("接受到的信息 ["" + string.Format("logout:{0}", this.name) + ""]");
                        if (Disconnected != null)
                            Disconnected(this, EventArgs.Empty);
                    }
                    else
                    {
                        if (DataReceived != null)
                        {
                            logger.Log("接受到的信息 ["" + messageReceived + ""]");
                            DataReceived(this, messageReceived, EventArgs.Empty);
                        }
                        Array.Clear(receivedDataBuffer, 0, receivedDataBuffer.Length);
                        ConnectionSocket.BeginReceive(receivedDataBuffer, 0, receivedDataBuffer.Length, 0, new AsyncCallback(Read), null);
                    }
                }
                catch (Exception ex)
                {
                    logger.Log(ex.Message);
                    logger.Log("Socket连接将会被终止。");
                    if (Disconnected != null)
                        Disconnected(this, EventArgs.Empty);
                }
            }
    
            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 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
                System.Security.Cryptography.MD5 MD5Service = System.Security.Cryptography.MD5.Create();
                return MD5Service.ComputeHash(concatenatedKeys);
            }
    
            public void ManageHandshake(IAsyncResult status)
            {
                string header = "Sec-WebSocket-Version:";
                int HandshakeLength = (int)status.AsyncState;
                byte[] last8Bytes = new byte[8];
    
                System.Text.UTF8Encoding decoder = new System.Text.UTF8Encoding();
                String rawClientHandshake = decoder.GetString(receivedDataBuffer, 0, HandshakeLength);
    
                Array.Copy(receivedDataBuffer, HandshakeLength - 8, last8Bytes, 0, 8);
    
                //现在使用的是比较新的Websocket协议
                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)
                    {
                        Console.WriteLine(Line);
                        if (Line.Contains("Sec-WebSocket-Key:"))
                        {
                            acceptKey = ComputeWebSocketHandshakeSecurityHash09(Line.Substring(Line.IndexOf(":") + 2));
                        }
                    }
    
                    New_Handshake = string.Format(New_Handshake, acceptKey);
                    byte[] newHandshakeText = Encoding.UTF8.GetBytes(New_Handshake);
                    ConnectionSocket.BeginSend(newHandshakeText, 0, newHandshakeText.Length, 0, HandshakeFinished, null);
                    return;
                }
    
                string ClientHandshake = decoder.GetString(receivedDataBuffer, 0, HandshakeLength - 8);
    
                string[] ClientHandshakeLines = ClientHandshake.Split(new string[] { Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries);
    
                logger.Log("新的连接请求来自" + ConnectionSocket.LocalEndPoint + "。正在准备连接 ...");
    
                // 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");
                        }
                }
                // Build the response for the client
                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("发送握手信息 ...");
                ConnectionSocket.BeginSend(serverHandshakeResponse, 0, HandshakeText.Length + 16, 0, HandshakeFinished, null);
                logger.Log(Handshake);
            }
    
            public static 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;
            }
    
            private void HandshakeFinished(IAsyncResult status)
            {
                ConnectionSocket.EndSend(status);
                ConnectionSocket.BeginReceive(receivedDataBuffer, 0, receivedDataBuffer.Length, 0, new AsyncCallback(Read), null);
                if (NewConnection != null) NewConnection("", EventArgs.Empty);
            }
        }
    
        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;
            }
    
        }
    
        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("无效的数据头.");
    
                //第一个字节
                _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);
    
                //第二个字节
                _maskcode = (buffer[1] & 0x80) == 0x80;
                _payloadlength = (sbyte)(buffer[1] & 0x7f);
    
            }
    
            //发送封装数据
            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;
                //第二个字节
                _maskcode = hasmask;
                _payloadlength = (sbyte)length;
            }
    
            //返回帧头字节
            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;
            }
        }
    }

    WebSocket客户端:

    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=gb2312">
        <title>Web sockets test</title>
        <style type="text/css">
            .container { font-family: "Courier New"; width: 680px; height: 300px; overflow: auto; border: 1px solid black; }
    
            .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; }
        </style>
    
        <script src="jquery-min.js" type="text/javascript"></script>
        <script type="text/javascript">
            var ws;
            var SocketCreated = false;
            var isUserloggedout = false;
    
            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() {
                if (SocketCreated && (ws.readyState == 0 || ws.readyState == 1)) {
                    lockOn("离开聊天室...");
                    SocketCreated = false;
                    isUserloggedout = true;
                    ws.close();
                } else {
                    lockOn("进入聊天室...");
                    Log("准备连接到聊天服务器 ...");
                    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) {
                        Log(ex, "ERROR");
                        return;
                    }
                    document.getElementById("ToggleConnection").innerHTML = "断开";
                    ws.onopen = WSonOpen;
                    ws.onmessage = WSonMessage;
                    ws.onclose = WSonClose;
                    ws.onerror = WSonError;
                }
            };
    
    
            function WSonOpen() {
                lockOff();
                Log("连接已经建立。", "OK");
                $("#SendDataContainer").show();
                ws.send("login:" + document.getElementById("txtName").value);
            };
    
            function WSonMessage(event) {
                Log(event.data);
            };
    
            function WSonClose() {
                lockOff();
                if (isUserloggedout)
                    Log("" + document.getElementById("txtName").value + "】离开了聊天室!");
                document.getElementById("ToggleConnection").innerHTML = "连接";
                $("#SendDataContainer").hide();
            };
    
            function WSonError() {
                lockOff();
                Log("远程连接中断。", "ERROR");
            };
    
    
            function SendDataClicked() {
                if (document.getElementById("DataToSend").value.trim() != "") {
                    ws.send(document.getElementById("txtName").value + "说 :"" + document.getElementById("DataToSend").value + """);
                    document.getElementById("DataToSend").value = "";
                }
            };
    
    
            function Log(Text, MessageType) {
                if (MessageType == "OK") Text = "<span style='color: green;'>" + Text + "</span>";
                if (MessageType == "ERROR") Text = "<span style='color: red;'>" + Text + "</span>";
                document.getElementById("LogContainer").innerHTML = document.getElementById("LogContainer").innerHTML + Text + "<br />";
                var LogContainer = document.getElementById("LogContainer");
                LogContainer.scrollTop = LogContainer.scrollHeight;
            };
    
    
            $(document).ready(function () {
                $("#SendDataContainer").hide();
                var WebSocketsExist = true;
                try {
                    var dummy = new WebSocket("ws://localhost:8989/test");
                } catch (ex) {
                    try {
                        webSocket = new MozWebSocket("ws://localhost:8989/test");
                    }
                    catch (ex) {
                        WebSocketsExist = false;
                    }
                }
    
                if (WebSocketsExist) {
                    Log("您的浏览器支持WebSocket. 您可以尝试连接到聊天服务器!", "OK");
                    document.getElementById("Connection").value = "192.168.1.108:4141/chat";
                } else {
                    Log("您的浏览器不支持WebSocket。请选择其他的浏览器再尝试连接服务器。", "ERROR");
                    document.getElementById("ToggleConnection").disabled = true;
                }
    
                $("#DataToSend").keypress(function (evt) {
                    if (evt.keyCode == 13) {
                        $("#SendData").click();
                        evt.preventDefault();
                    }
                })
            });
    
        </script>
    </head>
    <body>
        <div id="skm_LockPane" class="LockOff"></div>
        <form id="form1" runat="server">
            <h1>Web Socket 聊天室</h1>
            <br />
            <div>
                按下连接按钮,会通过WebSocket发起一个到聊天浏览器的连接。
            </div>
            服务器地址:
            <input type="text" id="Connection" />
            用户名:
            <input type="text" id="txtName" value="黄晓安" />
            <button id='ToggleConnection' type="button" onclick='ToggleConnectionClicked();'>连接</button>
            <br />
            <br />
            <div id='LogContainer' class='container'></div>
            <br />
            <div id='SendDataContainer'>
                <input type="text" id="DataToSend" size="88" />
                <button id='SendData' type="button" onclick='SendDataClicked();'>发送</button>
            </div>
            <br />
        </form>
    </body>
    </html>

    WebSocket 的局限性

    WebSocket 的优点已经列举得很多了,但是作为一个正在演变中的 Web 规范,我们也要看到目前用 Websocket 构建应用程序的一些风险。首先,WebSocket 规范目前还处于草案阶段,也就是它的规范和 API 还是有变动的可能,另外的一个风险就是微软的 IE 作为占市场份额最大的浏览器,和其他的主流浏览器相比,对 HTML5 的支持是比较差的,这是我们在构建企业级的 Web 应用的时候必须要考虑的一个问题。

    具体详解地址:http://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/

  • 相关阅读:
    爱上经典之《大公鸡》
    爱上经典之罗大佑《光阴故事》
    wamp安装Zend Optimizer 报错
    【转】oracle客户端精简绿色版环境变量配置
    请问C#中string是值传递还是引用传递?
    ArcEngine 固定比例放大缩小
    【转】POSITION: absolute,与 relative区别
    浪潮巅峰
    【转】使用远程桌面鼠标移动缓慢问题的解决方法
    【转】访问 IIS 元数据库失败
  • 原文地址:https://www.cnblogs.com/yxlblogs/p/3896715.html
Copyright © 2020-2023  润新知