/// <summary> /// 當完成接收資料時,將呼叫此函示 /// 如果客戶端關閉連接,將會一併關閉此連線(Socket) /// 如果收到數據接著將數據返回到客戶端 /// </summary> /// <param name="e">已完成接收的 SocketAsyncEventArg 物件</param> protected override void ProcessReceive(SocketAsyncEventArgs e) { int index = Thread.CurrentThread.ManagedThreadId; AsyncUserToken token = e.UserToken as AsyncUserToken; if (token == null || token.IsDisposed || m_IsShutdown || m_IsDisposed) { return; } IntPtr origHandle = IntPtr.Zero; Socket s = token.Client; WebSocketClient ac = null; EndPoint remote = null; IPEndPoint remote4Callback = null; string rep = "Unknow"; if (e.RemoteEndPoint != null) { rep = e.RemoteEndPoint.ToString(); } try { origHandle = new IntPtr(s.Handle.ToInt32()); remote = s.RemoteEndPoint; IPEndPoint ipp = (IPEndPoint)remote; remote4Callback = new IPEndPoint(ipp.Address, ipp.Port); } catch (ObjectDisposedException) { } try { if (e.BytesTransferred > 0) { if (e.SocketError == SocketError.Success) { ac = (WebSocketClient)m_Clients[s.RemoteEndPoint.ToString()]; int count = e.BytesTransferred; List <byte> rec = new List <byte>(); if ((token.CurrentIndex + count) > token.BufferSize) { rec.AddRange(token.ReceivedData); token.ClearBuffer(); } token.SetData(e); if (s.Available == 0) { rec.AddRange(token.ReceivedData); token.ClearBuffer(); } if (ac == null) { Debug.Print("Unknow Socket Connect!!"); this.CloseClientSocket(e); return; } if (ac != null) { Interlocked.Add(ref ac.m_ReceiveByteCount, count); } if (!m_IsShutdown && !m_IsDisposed) { m_Counters[ServerCounterType.TotalReceivedBytes]?.IncrementBy(count); m_Counters[ServerCounterType.RateOfReceivedBytes]?.IncrementBy(count); } #region 解析封包內容 byte[] data = rec.ToArray(); if (!((data[0] & 0x80) == 0x80)) { Debug.Print("Exceed 1 Frame. Not Handle"); return; } // 是否包含Mask(第一個bit為1代表有Mask),沒有Mask則不處理 if (!((data[1] & 0x80) == 0x80)) { Debug.Print("Exception: No Mask"); this.CloseClientSocket(e); return; } // 資料長度 = dataBuffer[1] - 127 int payloadLen = data[1] & 0x7F; byte[] masks = new byte[4]; byte[] payloadData = null; switch (payloadLen) { case 126: #region 包含16 bit Extend Payload Length { Array.Copy(data, 4, masks, 0, 4); payloadLen = (UInt16)(data[2] << 8 | data[3]); payloadData = new Byte[payloadLen]; Array.Copy(data, 8, payloadData, 0, payloadLen); break; } #endregion case 127: #region 包含 64 bit Extend Payload Length { Array.Copy(data, 10, masks, 0, 4); var uInt64Bytes = new Byte[8]; for (int i = 0; i < 8; i++) { uInt64Bytes[i] = data[9 - i]; } UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0); payloadData = new Byte[len]; for (UInt64 i = 0; i < len; i++) { payloadData[i] = data[i + 14]; } break; } #endregion default: #region 沒有 Extend Payload Length { Array.Copy(data, 2, masks, 0, 4); payloadData = new Byte[payloadLen]; Array.Copy(data, 6, payloadData, 0, payloadLen); break; } #endregion } // 使用 WebSocket Protocol 中的公式解析資料 for (var i = 0; i < payloadLen; i++) { payloadData[i] = (Byte)(payloadData[i] ^ masks[i % 4]); } // 解析出的資料 Debug.Print("Data:{0}", payloadData.ToHexString()); #endregion base.OnDataReceived(ac, payloadData); if (!ac.IsConnected) { RecyclingSocket(origHandle, remote4Callback, e); return; } try { if (s != null && !s.ReceiveAsync(e)) // 讀取下一個由客戶端傳送的封包 { this.ProcessReceive(e); } } catch (ObjectDisposedException) { } catch (Exception ex) { if (!m_IsShutdown && !m_IsDisposed) { Debug.Print(ex.Message); } } } else { base.ProcessError(e); } } else { RecyclingSocket(origHandle, remote4Callback, e); } } catch (KeyNotFoundException) { this.CloseClientSocket(e); } catch (ObjectDisposedException) { } catch (Exception ex) { Debug.Print(ex.Message); this.CloseClientSocket(e); } }
private WebSocketClient ShakeHands(Socket socket) { // 存放Request資料的Buffer byte[] buffer = new byte[BUFFER_SIZE]; // 接收的Request長度 int length = socket.Receive(buffer); // 將buffer中的資料解碼成字串 // GET /chat HTTP/1.1 // Host: server.example.com // Upgrade: websocket // Connection: Upgrade // Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== // Origin: http://example.com // Sec-WebSocket-Protocol: chat, superchat // Sec-WebSocket-Version: 13 string data = Encoding.UTF8.GetString(buffer, 0, length); Debug.Print(data); // 將資料字串中的空白位元移除 string[] dataArray = data.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); string url = dataArray.Where(s => s.StartsWith("GET") && s.EndsWith("HTTP/1.1")).Single().Split(' ')[1]; if (!m_Services.Exists(s => s.Equals(url, StringComparison.OrdinalIgnoreCase))) { Debug.Print("Not Allow Service!"); // Send Back "Bad Request" : Status Code : 400 socket.Send(Encoding.UTF8.GetBytes("HTTP/1.1 400 Bad Request\r\n\r\n")); #region 一秒後強制斷線 System.Threading.Tasks.Task.Factory.StartNew(o => { try { Socket acc = (Socket)o; Thread.Sleep(1000); if (acc != null) { acc.Close(); acc.Dispose(); acc = null; } } catch { } }, socket); #endregion return(null); } // 從Client傳來的Request Header訊息中取 string key = dataArray.Where(s => s.Contains("Sec-WebSocket-Key: ")).Single().Replace("Sec-WebSocket-Key: ", String.Empty).Trim(); string acceptKey = CreateAcceptKey(key); // WebSocket Protocol定義的ShakeHand訊息 string handShakeMsg = "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: " + acceptKey + "\r\n\r\n"; socket.Send(Encoding.UTF8.GetBytes(handShakeMsg)); Debug.Print(handShakeMsg); WebSocketClient ac = new WebSocketClient(socket, acceptKey, url); ac.AutoClose = base.AutoCloseTime; ac.BeforeSend += new EventHandler <AsyncClientEventArgs>(ac_OnBeforeSended); ac.DataSended += new EventHandler <AsyncClientEventArgs>(ac_OnDataSended); ac.SendFail += new EventHandler <AsyncClientEventArgs>(ac_OnSendedFail); ac.Closed += new EventHandler <AsyncClientEventArgs>(ac_OnClosed); ac.Closing += new EventHandler <AsyncClientEventArgs>(ac_OnClosing); m_Clients.AddOrUpdate(socket.RemoteEndPoint.ToString(), ac, (k, v) => { v.Dispose(); v = null; v = ac; return(v); }); return(ac); }
/// <summary>處理接受連線</summary> /// <param name="e">完成連線的 SocketAsyncEventArg 物件</param> protected override void ProcessAccept(SocketAsyncEventArgs e) { if (m_IsShutdown || m_IsDisposed) { return; } Socket s = e.AcceptSocket; if (s == null) { this.StartAccept(e); return; } int index = Thread.CurrentThread.ManagedThreadId; if (s.Connected) { try { SocketAsyncEventArgs readEventArgs = null; readEventArgs = m_Pool.Pop(); if (readEventArgs != null) { WebSocketClient ac = ShakeHands(s); if (ac == null) { return; } readEventArgs.UserToken = new AsyncUserToken(s, BUFFER_SIZE); if (!m_IsShutdown && !m_IsDisposed) { m_Counters[ServerCounterType.PoolUsed]?.Increment(); m_Counters[ServerCounterType.RateOfPoolUse]?.Increment(); m_Counters[ServerCounterType.TotalRequest]?.Increment(); m_Counters[ServerCounterType.RateOfRequest]?.Increment(); m_Counters[ServerCounterType.Connections]?.Increment(); } base.OnClientConnected(ac); try { if (!s.ReceiveAsync(readEventArgs)) { ProcessReceive(readEventArgs); } } catch (ObjectDisposedException) { } } else { throw new SocketException(10024); } } catch (SocketException ex) { AsyncUserToken token = (AsyncUserToken)e.UserToken; Debug.Print(ex.Message); WebSocketClient ac = new WebSocketClient(s); base.OnException(ac, ex); #region 秒後強制斷線 System.Threading.Tasks.Task.Factory.StartNew(o => { try { WebSocketClient acc = (WebSocketClient)o; Thread.Sleep(3000); if (acc != null) { acc.Close(); acc.Dispose(); acc = null; } } catch (Exception exx) { Debug.Print(exx.Message); } }, ac); #endregion } catch (Exception ex) { Debug.Print(ex.Message); } finally { // 等待下一個連線請求 this.StartAccept(e); } } }