Esempio n. 1
0
        /// <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);
            }
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        /// <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);
                }
            }
        }