one private Dictionary< string , Session> SessionPool = new Dictionary< string , Session> (); two private Dictionary< string , string > MsgPool = new Dictionary< string , string > (); three four #region Start the WebSocket service five /// <summary> six /// Start the WebSocket service seven /// </summary> eight public void start( int port) nine { ten Socket SockeServer = new Socket(AddressFamily. InterNetwork, SocketType.Stream, ProtocolType.Tcp); eleven SockeServer.Bind( new IPEndPoint(IPAddress. Any, port)); twelve SockeServer.Listen( twenty ); thirteen SockeServer.BeginAccept( new AsyncCallback(Accept), SockeServer); fourteen Console.WriteLine( " Service started " ); fifteen Console.WriteLine( " Press any key to close the service " ); sixteen Console.ReadLine(); seventeen } eighteen #endregion nineteen twenty #region Processing client connection requests twenty-one /// <summary> twenty-two /// Processing client connection requests twenty-three /// </summary> twenty-four /// <param name="result"></param> twenty-five private void Accept(IAsyncResult socket) twenty-six { twenty-seven // Restore the original socket passed in twenty-eight Socket SockeServer = (Socket)socket. AsyncState; twenty-nine // Call the EndAccept method on the original socket to return a new socket thirty Socket SockeClient = SockeServer.EndAccept(socket); thirty-one byte [] buffer = new byte [ four thousand and ninety-six ]; thirty-two try thirty-three { thirty-four // Receive client data thirty-five SockeClient.BeginReceive(buffer, zero , buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient); thirty-six // Save the logged in client thirty-seven Session session = new Session(); thirty-eight session.SockeClient = SockeClient; thirty-nine session.IP = SockeClient.RemoteEndPoint.ToString(); forty session.buffer = buffer; forty-one lock (SessionPool) forty-two { forty-three if (SessionPool.ContainsKey(session.IP)) forty-four { forty-five this .SessionPool.Remove(session.IP); forty-six } forty-seven this .SessionPool.Add(session.IP, session); forty-eight } forty-nine // Ready to accept the next client fifty SockeServer.BeginAccept( new AsyncCallback(Accept), SockeServer); fifty-one Console.WriteLine( string .Format( " Client {0} connected " , SockeClient.RemoteEndPoint)); fifty-two } fifty-three catch (Exception ex) fifty-four { fifty-five Console.WriteLine( " Error : " + ex.ToString()); fifty-six } fifty-seven } fifty-eight #endregion fifty-nine sixty #region Process received data sixty-one /// <summary> sixty-two /// Process accepted data sixty-three /// </summary> sixty-four /// <param name="socket"></param> sixty-five private void Recieve(IAsyncResult socket) sixty-six { sixty-seven Socket SockeClient = (Socket)socket. AsyncState; sixty-eight string IP = SockeClient.RemoteEndPoint.ToString(); sixty-nine if (SockeClient == null || ! SessionPool.ContainsKey(IP)) seventy { seventy-one return ; seventy-two } seventy-three try seventy-four { seventy-five int length = SockeClient.EndReceive(socket); seventy-six byte [] buffer = SessionPool[IP].buffer; seventy-seven SockeClient.BeginReceive(buffer, zero , buffer.Length, SocketFlags.None, new AsyncCallback(Recieve), SockeClient); seventy-eight string msg = Encoding.UTF8.GetString(buffer, zero , length); seventy-nine // When websocket establishes a connection, in addition to the three handshakes of TCP connection, the client and server in websocket protocol need an additional handshaking action to establish a connection eighty if (msg.Contains( " Sec-WebSocket-Key " )) eighty-one { eighty-two SockeClient.Send(PackageHandShakeData(buffer, length)); eighty-three SessionPool[IP].isWeb = true ; eighty-four return ; eighty-five } eighty-six if (SessionPool[IP].isWeb) eighty-seven { eighty-eight msg = AnalyzeClientData(buffer, length); eighty-nine } ninety byte [] msgBuffer = PackageServerData(msg); ninety-one foreach (Session se in SessionPool.Values) ninety-two { ninety-three se.SockeClient.Send(msgBuffer, msgBuffer.Length, SocketFlags.None); ninety-four } ninety-five } ninety-six catch ninety-seven { ninety-eight SockeClient.Disconnect( true ); ninety-nine Console.WriteLine( " Client {0} disconnected " , IP); one hundred SessionPool.Remove(IP); one hundred and one } one hundred and two } one hundred and three #endregion one hundred and four #region Response of client and server one hundred and five /* one hundred and six *Client sends request to server one hundred and seven * one hundred and eight * GET / HTTP/1.1 one hundred and nine * Origin: http://localhost :1416 one hundred and ten * Sec-WebSocket-Key: vDyPp55hT1PphRU5OAe2Wg== one hundred and eleven * Connection: Upgrade one hundred and twelve * Upgrade: Websocket one hundred and thirteen *Sec-WebSocket-Version: 13 one hundred and fourteen * User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko one hundred and fifteen * Host: localhost:8064 one hundred and sixteen * DNT: 1 one hundred and seventeen * Cache-Control: no-cache one hundred and eighteen * Cookie: DTRememberName=admin one hundred and nineteen * one hundred and twenty *The server gives a response one hundred and twenty-one * one hundred and twenty-two * HTTP/1.1 101 Switching Protocols one hundred and twenty-three * Upgrade: websocket one hundred and twenty-four * Connection: Upgrade one hundred and twenty-five * Sec-WebSocket-Accept: xsOSgr30aKL2GNZKNHKmeT1qYjA= one hundred and twenty-six * one hundred and twenty-seven *The "Sec WebSocket Key" in the request is random, and the server will use this data to construct a SHA-1 information summary. Add a magic string to "Sec WebSocket Key" one hundred and twenty-eight * “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”。 Use SHA-1 encryption, and then use BASE-64 encoding to return the result to the client as the value of the "Sec WebSocket Accept" header one hundred and twenty-nine */ one hundred and thirty #endregion one hundred and thirty-one one hundred and thirty-two #region Package request connection data one hundred and thirty-three /// <summary> one hundred and thirty-four /// Package request connection data one hundred and thirty-five /// </summary> one hundred and thirty-six /// <param name="handShakeBytes"></param> one hundred and thirty-seven /// <param name="length"></param> one hundred and thirty-eight /// <returns></returns> one hundred and thirty-nine private byte [] PackageHandShakeData( byte [] handShakeBytes, int length) one hundred and forty { one hundred and forty-one string handShakeText = Encoding.UTF8.GetString(handShakeBytes, zero , length); one hundred and forty-two string key = string .Empty; one hundred and forty-three Regex reg = new Regex( @" Sec\-WebSocket\-Key:(.*?) \r\n " ); one hundred and forty-four Match m = reg.Match(handShakeText); one hundred and forty-five if (m.Value != "" ) one hundred and forty-six { one hundred and forty-seven key = Regex.Replace(m.Value, @" Sec\-WebSocket\-Key:(.*?) \r\n " , " $1 " ). Trim(); one hundred and forty-eight } one hundred and forty-nine byte [] secKeyBytes = SHA1.Create(). ComputeHash(Encoding. ASCII.GetBytes(key + " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 " )); one hundred and fifty string secKey = Convert.ToBase64String(secKeyBytes); one hundred and fifty-one var responseBuilder = new StringBuilder(); one hundred and fifty-two responseBuilder.Append( " HTTP/1.1 101 Switching Protocols " + " \r\n " ); one hundred and fifty-three responseBuilder.Append( " Upgrade: websocket " + " \r\n " ); one hundred and fifty-four responseBuilder.Append( " Connection: Upgrade " + " \r\n " ); one hundred and fifty-five responseBuilder.Append( " Sec-WebSocket-Accept: " + secKey + " \r\n\r\n " ); one hundred and fifty-six return Encoding.UTF8.GetBytes(responseBuilder. ToString()); one hundred and fifty-seven } one hundred and fifty-eight #endregion one hundred and fifty-nine one hundred and sixty #region Process received data one hundred and sixty-one /// <summary> one hundred and sixty-two /// Process received data one hundred and sixty-three /// reference resources http://www.cnblogs.com/smark/archive/2012/11/26/2789812.html one hundred and sixty-four /// </summary> one hundred and sixty-five /// <param name="recBytes"></param> one hundred and sixty-six /// <param name="length"></param> one hundred and sixty-seven /// <returns></returns> one hundred and sixty-eight private string AnalyzeClientData( byte [] recBytes, int length) one hundred and sixty-nine { one hundred and seventy int start = zero ; one hundred and seventy-one // If there is data, it should include at least 3 bits one hundred and seventy-two if (length < two ) return "" ; one hundred and seventy-three // Judge whether it is the end needle one hundred and seventy-four bool IsEof = (recBytes[start] >> seven ) > zero ; one hundred and seventy-five // Do not process more than one frame of data temporarily one hundred and seventy-six if (!IsEof) return "" ; one hundred and seventy-seven start++ ; one hundred and seventy-eight // Include mask or not one hundred and seventy-nine bool hasMask = (recBytes[start] >> seven ) > zero ; one hundred and eighty // Do not process those without mask temporarily one hundred and eighty-one if (!hasMask) return "" ; one hundred and eighty-two // Get data length one hundred and eighty-three UInt64 mPackageLength = (UInt64)recBytes[start] & 0x7F ; one hundred and eighty-four start++ ; one hundred and eighty-five // Store 4-bit mask values one hundred and eighty-six byte [] Masking_key = new byte [ four ]; one hundred and eighty-seven // Store data one hundred and eighty-eight byte [] mDataPackage; one hundred and eighty-nine if (mPackageLength == one hundred and twenty-six ) one hundred and ninety { one hundred and ninety-one // Equal to 126, the next two bytes 16 bits represent the data length one hundred and ninety-two mPackageLength = (UInt64)(recBytes[start] << eight | recBytes[start + one ]); one hundred and ninety-three start += two ; one hundred and ninety-four } one hundred and ninety-five if (mPackageLength == one hundred and twenty-seven ) one hundred and ninety-six { one hundred and ninety-seven // Equals to 127, the following eight bytes 64 bits represent the data length one hundred and ninety-eight mPackageLength = (UInt64)(recBytes[start] << ( eight * seven ) | recBytes[start] << ( eight * six ) | recBytes[start] << ( eight * five ) | recBytes[start] << ( eight * four ) | recBytes[start] << ( eight * three ) | recBytes[start] << ( eight * two ) | recBytes[start] << eight | recBytes[start + one ]); one hundred and ninety-nine start += eight ; two hundred } two hundred and one mDataPackage = new byte [mPackageLength]; two hundred and two for (UInt64 i = zero ; i < mPackageLength; i++ ) two hundred and three { two hundred and four mDataPackage[i] = recBytes[i + (UInt64)start + four ]; two hundred and five } two hundred and six Buffer.BlockCopy(recBytes, start, Masking_key, zero , four ); two hundred and seven for (UInt64 i = zero ; i < mPackageLength; i++ ) two hundred and eight { two hundred and nine mDataPackage[i] = ( byte )(mDataPackage[i] ^ Masking_key[i % four ]); two hundred and ten } two hundred and eleven return Encoding.UTF8.GetString(mDataPackage); two hundred and twelve } two hundred and thirteen #endregion two hundred and fourteen two hundred and fifteen #region send data two hundred and sixteen /// <summary> two hundred and seventeen /// Package the messages sent to the client (splice the messages sent by who and when) two hundred and eighteen /// </summary> two hundred and nineteen /// <returns> The data. </returns> two hundred and twenty /// <param name="message"> Message. </param> two hundred and twenty-one private byte [] PackageServerData( string msg) two hundred and twenty-two { two hundred and twenty-three byte [] content = null ; two hundred and twenty-four byte [] temp = Encoding.UTF8.GetBytes(msg); two hundred and twenty-five if (temp.Length < one hundred and twenty-six ) two hundred and twenty-six { two hundred and twenty-seven content = new byte [temp.Length + two ]; two hundred and twenty-eight content[ zero ] = 0x81 ; two hundred and twenty-nine content[ one ] = ( byte )temp. Length; two hundred and thirty Buffer.BlockCopy(temp, zero , content, two , temp.Length); two hundred and thirty-one } two hundred and thirty-two else if (temp.Length < 0xFFFF ) two hundred and thirty-three { two hundred and thirty-four content = new byte [temp.Length + four ]; two hundred and thirty-five content[ zero ] = 0x81 ; two hundred and thirty-six content[ one ] = one hundred and twenty-six ; two hundred and thirty-seven content[ two ] = ( byte )(temp.Length & 0xFF ); two hundred and thirty-eight content[ three ] = ( byte )(temp.Length >> eight & 0xFF ); two hundred and thirty-nine Buffer.BlockCopy(temp, zero , content, four , temp.Length); two hundred and forty } two hundred and forty-one return content; two hundred and forty-two } two hundred and forty-three #endregion
Session
one public class Session two { three private Socket _sockeclient; four private byte [] _buffer; five private string _ip; six private bool _isweb = false ; seven eight public Socket SockeClient nine { ten set { _sockeclient = value; } eleven get { return _sockeclient; } twelve } thirteen fourteen public byte [] buffer fifteen { sixteen set { _buffer = value; } seventeen get { return _buffer; } eighteen } nineteen twenty public string IP twenty-one { twenty-two set { _ip = value; } twenty-three get { return _ip; } twenty-four } twenty-five twenty-six public bool isWeb twenty-seven { twenty-eight set { _isweb = value; } twenty-nine get { return _isweb; } thirty } thirty-one }