首页 > 代码库 > HTML5学习之WebSocket通讯(六)

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/