Ejemplo n.º 1
0
        //protected DateTime m_connectDT;
        //public DateTime ConnectDT { get { return m_connectDT; } }
        //protected DateTime m_activeDT;
        //public DateTime ActiveDT { get { return m_activeDT; } }

        public BufferProcessor(AsyncSocketServer asyncSocketServer, SocketUserToken userToken)
        {
            m_asyncSocketServer = asyncSocketServer;
            m_userToken = userToken;
            m_packageOffset = 0;
            m_readyPackage = 0;
        }
Ejemplo n.º 2
0
 public void Add(string UserID, SocketUserToken userToken)
 {
     lock (m_table.SyncRoot)
     {
         m_table.Add(UserID, userToken);
         //收集監視器數據之在線數統計-增加
         LxTcpServer.SrvMonitor.ServerStatistics.OnlineStatAdd(userToken.BindingUser.Role);
     }
 }
Ejemplo n.º 3
0
        protected bool m_sendAsync; //標識是否有發送異步事件

        //protected DateTime m_connectDT;
        //public DateTime ConnectDT { get { return m_connectDT; } }
        //protected DateTime m_activeDT;
        //public DateTime ActiveDT { get { return m_activeDT; } }

        public AsyncSendAgent(AsyncSocketServer asyncSocketServer, SocketUserToken userToken)
        {
            m_asyncSocketServer = asyncSocketServer;
            m_socketUserToken = userToken;

            m_sendAsync = false;

            //m_connectDT = DateTime.UtcNow;
            //m_activeDT = DateTime.UtcNow;
        }
Ejemplo n.º 4
0
 public void Push(SocketUserToken item)
 {
     if (item == null)
     {
         throw new ArgumentException("Items added to a SocketUserToken cannot be null");
     }
     lock (m_pool)
     {
         m_pool.Push(item);
     }
 }
Ejemplo n.º 5
0
        ///// <summary>
        ///// 收集監視器數據之登錄統計開始
        ///// </summary>
        //private void LoginStatStart()
        //{
        //    //登錄當前并發數
        //    ServerStatistics.Concurrent_Login++;
        //    //登錄最高并發數
        //    if (ServerStatistics.MaxConcurrent_Login < ServerStatistics.Concurrent_Login)
        //        ServerStatistics.MaxConcurrent_Login = ServerStatistics.Concurrent_Login;
        //}

        ///// <summary>
        ///// 收集監視器數據之登錄統計結束
        ///// </summary>
        //private void LoginStatEnd(long ElapsedMilliseconds)
        //{
        //    //登錄當前并發數
        //    ServerStatistics.Concurrent_Login--;
        //    //登錄當前執行時長(ms)
        //    ServerStatistics.DurationTime_Login = (int)ElapsedMilliseconds;
        //    //登錄最大執行時長(ms)
        //    if (ServerStatistics.MaxDurationTime_Login < ServerStatistics.DurationTime_Login)
        //        ServerStatistics.MaxDurationTime_Login = ServerStatistics.DurationTime_Login;
        //}

        /// <summary>
        /// 處理用戶登錄
        /// </summary>
        /// <param name="userToken"></param>
        /// <returns></returns>
        private bool ProcessLogin(SocketUserToken userToken)
        {
            bool Done = false;
            Stopwatch sw = new Stopwatch();
            try
            {
                //收集監視器數據之登錄統計開始
                ServerStatistics.LoginStatStart();
                //開始計時
                sw.Start();

                //返回解包后的資料(返回數組 0=type ; 1=終端; 2=群號; 3=時間; 4=消息ID; 5=消息內容; 6=終端姓名)
                // type = "0" 是PC登錄; type = "WS" 是Web登錄
                int logDataLength = 0;
                object[] ReceiveData = ParseProtocol.ParseLoginData(userToken.ReceiveEventArgs.Buffer, out logDataLength);
                string DataType = ReceiveData[0].ToString();
                string DataTerminal = ReceiveData[1].ToString();
                //登錄時群號規則: 普通PC用戶登錄時為空格, 外接應用(APP)登錄時為"APP", 訂閱號登錄時為"SUB", 文件傳輸時為"FILE", 語音通話登錄時為"AUDIO"
                //移動設備登錄為: iPhone = "IPHONE"
                //                iPad = "IPAD"
                //                Android Phone = "APHONE"
                //                Android Pad = "APAD"
                string DataGroup = ReceiveData[2].ToString();
                //保存用戶設備網卡的Mac地址
                string DataTerminalName = ReceiveData[6].ToString();
                //手機登錄時,包體就是用戶手機(iOS)的Token.
                //文件傳送時,包體就是文件發送者|文件接收者.
                //PC端登錄時,包體就是PC設備名稱.
                //語音通話時,包體就是語音通話發起者|語音通話接收者.
                string DataText = ReceiveData[5].ToString();

                if (DataType == "0" && DataTerminal.Length > 0)
                {
                    string UserID = DataTerminal; // 用戶帳號
                    bool Passed = true;
                    //生成異步發送代理
                    if (userToken.AsyncSendAgent == null)
                        userToken.AsyncSendAgent = new AsyncSendAgent(this, userToken);
                    switch (DataGroup.ToUpper())
                    {
                        case "SUB":

                            #region " 訂閱號登錄 "

                            Done = DoSubServiceLogin(UserID, DataTerminalName, DataGroup, DataText, userToken, m_subServiceTokenList);
                            if (!Done)
                                LogHelper.WriteLog("ProcessLogin", "#Error.完成登錄驗證,但服務器拒絕用戶登錄.");

                            #endregion

                            break;

                        case "APP":

                            #region " APP登錄 "

                            try
                            {
                                List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, DataGroup, Guid.NewGuid().ToString().Replace("-", "").ToUpper(), "");
                                //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                                lock (userToken.ConnectSocket)
                                {
                                    foreach (byte[] msg in msgs)
                                    {
                                        Passed = userToken.AsyncSendAgent.DoSendBuffer(msg);
                                        if (!Passed)
                                            break;
                                        //userToken.ConnectSocket.Send(msg);
                                        //SendData(userToken.ConnectSocket, msg);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Passed = false;
                                LogHelper.WriteLog("ProcessLogin()", "發送登錄成功信息時" + (ex != null ? ex.Message : ""));
                            }

                            if (Passed)
                            {
                                //創建連接對象
                                userToken.BindingUser = new User();
                                userToken.BindingUser.State = User.UserStates.Online;
                                userToken.BindingUser.Role = User.UserRole.APP;
                                userToken.BindingUser.ID = UserID;
                                //Socket newClient = userToken.ConnectSocket;

                                // 將新連接加入轉發表並創建線程為其服務
                                // Key-GUID永不重複.
                                //添加到正在執行的列表中
                                m_appUserTokenList.Add(UserID, userToken);
                                //System.Diagnostics.Debug.WriteLine(UserID + " Logged in at " + DateTime.Now.ToString("HH:mm:ss:fff"));
                                Done = true;
                            }

                            #endregion

                            break;

                        case "FILE":

                            #region " 文件傳送帳號登錄 "
                            Passed = true;

                            if (Passed)
                            {
                                //創建連接對象
                                userToken.BindingUser = new User();
                                userToken.BindingUser.State = User.UserStates.Online;
                                userToken.BindingUser.Role = User.UserRole.FileTransfer;
                                userToken.BindingUser.ID = UserID;
                                userToken.BindingUser.Type = "F";
                                userToken.BindingUser.SenderID = DataText.Split(new char[] { '|' })[0].Trim();
                                userToken.BindingUser.ReceiverID = DataText.Split(new char[] { '|' })[1].Trim();
                                //Socket newClient = userToken.ConnectSocket;

                                // 將新連接加入轉發表並創建線程為其服務
                                // Key-GUID永不重複
                                m_fileUserTokenList.Add(UserID, userToken);
                                // 如果是接收者(R),會在構造方法里向發送者(S)發允許建立T通道的請求
                                Done = true;
                            }

                            #endregion

                            break;
                        case "AUDIO":

                            #region " 語音通話帳號登錄 "
                            Passed = true;
                            if (Passed)
                            {
                                //創建連接對象
                                userToken.BindingUser = new User();
                                userToken.BindingUser.State = User.UserStates.Online;
                                userToken.BindingUser.Role = User.UserRole.AudioCall;
                                userToken.BindingUser.ID = UserID;
                                //T通道登錄時才有名稱
                                userToken.BindingUser.Name = DataTerminalName;
                                userToken.BindingUser.Type = "A";
                                userToken.BindingUser.SenderID = DataText.Split(new char[] { '|' })[0].Trim();
                                userToken.BindingUser.ReceiverID = DataText.Split(new char[] { '|' })[1].Trim();
                                //Socket newClient = userToken.ConnectSocket;

                                // 將新連接加入轉發表並創建線程為其服務
                                // Key-GUID永不重複
                                m_audioCallTokenList.Add(UserID, userToken);
                                // 如果是接收者(R),會在構造方法里向發送者(S)發允許建立T通道的請求
                                Done = true;
                            }
                            #endregion

                            break;
                        default:

                            //取消日誌
                            //LogHelper.WriteLog("ProcessReceive", string.Format("#4.解析出登錄數據:{0} [{1}],準備執行登錄操作.", DataTerminal, userToken.ConnectSocket.RemoteEndPoint));

                            #region " PC端/Mobile登錄 "

                            Done = DoPcMobileLogin(UserID, DataTerminalName, DataGroup, DataText, userToken, DataGroup.Length > 0 ? m_mobileUserTokenList : m_pcUserTokenList);

                            if (!Done)
                                LogHelper.WriteLog("ProcessLogin", "#Error.完成登錄驗證,但服務器拒絕用戶登錄.");

                            #endregion

                            break;
                    }
                }
                else if (DataType == "WS" && DataTerminal.Length > 0)
                {
                    #region " Web端登錄 "

                    //UserID = DataTerminal; // 用戶帳號
                    //bool Passed = true;
                    ////Socket curSkt = _ws_transmit_tb[DataTerminal] as Socket;
                    //UserSocket User = _ws_transmit_tb[DataTerminal] as UserSocket;
                    //if (User != null)
                    //{
                    //    Socket curSkt = User.Socket;

                    //    #region " 發送離線 "
                    //    try
                    //    {
                    //        byte[] msg = WebConvertMethod.ConvertMsgToByte("00", "7", DataTerminal, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper());

                    //        //如果2秒內得不到之前登陸的對象,就直接干掉
                    //        //否則此帳號將永遠無法登錄
                    //        if (Monitor.TryEnter(curSkt, 2000))
                    //        {
                    //            try
                    //            {
                    //                //向用戶本人發送離線
                    //                curSkt.Send(msg);
                    //                //SendData(curSkt, msg);
                    //            }
                    //            catch
                    //            { }
                    //            finally
                    //            {
                    //                Monitor.Exit(curSkt);
                    //            }
                    //        }
                    //        else
                    //        {
                    //            //如果到這里說明之前登陸的對象已經死鎖                                            
                    //        }
                    //        //curSkt.Send(msg);

                    //        UpdateUserLog(UserID, "0", "1", "因相同帳號再次登錄而強制離線.");

                    //        //clsClientLog.WriteLog(clsClientLog.LogType.Error, "WebThreadFunc(object obj):default", "相同帳號異地登陸:" + DataTerminal + " " + DataTerminalName);
                    //        //LogHelper.WriteLog("StartUp()", "手機端相同帳號重複登陸:" + DataTerminal + "-" + DataTerminalName);
                    //    }
                    //    catch (SocketException ex)
                    //    {
                    //        //clsClientLog.WriteLog(clsClientLog.LogType.Error, "WebThreadFunc(object obj):default", "轉發發送離線消息時:" + ex.Message);
                    //        //LogHelper.WriteLog("StartUp()", "轉發發送離線消息時" + (ex != null ? ex.Message : ""));
                    //        LogHelper.WriteLog("StartUp()", "轉發手機用戶" + UserID + "離線消息時:" + (ex != null ? ex.Message : ""));
                    //    }
                    //    try
                    //    {
                    //        if (curSkt.Connected)
                    //        {
                    //            curSkt.Shutdown(SocketShutdown.Both);
                    //            //curSkt.Disconnect(false);
                    //        }
                    //        curSkt.Close();
                    //        curSkt = null;

                    //        Thread thread = _ws_thread_tb[DataTerminal] as Thread;
                    //        if (thread != null)
                    //        {
                    //            thread.Abort();
                    //            //線程池不會被遍歷,不鎖.
                    //            _ws_thread_tb.Remove(DataTerminal);
                    //        }
                    //        lock (_ws_transmit_tb.SyncRoot)
                    //            _ws_transmit_tb.Remove(DataTerminal);
                    //    }
                    //    catch (SocketException ex)
                    //    {
                    //        //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "嘗試關閉用戶" + DataTerminal + "線程和Socket連接時出錯." + (ex != null ? ex.Message : ""));
                    //        LogHelper.WriteLog("StartUp()", "嘗試關閉手機用戶" + DataTerminal + "線程和Socket連接時出錯." + (ex != null ? ex.Message : ""));
                    //    }
                    //    #endregion
                    //}
                    //// 驗證是否為唯一用戶
                    //if (_ws_transmit_tb.Count != 0 && _ws_transmit_tb.ContainsKey(UserID))
                    //{
                    //    try
                    //    {
                    //        byte[] msg = WebConvertMethod.ConvertMsgToByte("登錄失敗.", "3", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper());
                    //        lock (newClient)
                    //        {
                    //            newClient.Send(msg);
                    //            //SendData(newClient, msg);
                    //        }
                    //        LogHelper.WriteLog("StartUp()", "手機端" + DataTerminal + "登錄失敗");
                    //    }
                    //    catch (SocketException ex)
                    //    {
                    //        //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():驗證是否為唯一用戶", "發送登陸失敗信息時:" + ex.Message);
                    //        LogHelper.WriteLog("StartUp()", "發送登陸失敗信息時" + (ex != null ? ex.Message : ""));
                    //    }
                    //}
                    //else
                    //{
                    //    // 服務器開放登錄功能
                    //    try
                    //    {
                    //        byte[] msg = WebConvertMethod.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper());
                    //        //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                    //        lock (newClient)
                    //        {
                    //            newClient.Send(msg);
                    //            //SendData(newClient, msg);
                    //        }
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        Passed = false;
                    //        //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():服務器開放登錄功能", "發送登陸成功信息時:" + ex.Message);
                    //        LogHelper.WriteLog("StartUp()", "發送登錄成功信息時" + (ex != null ? ex.Message : ""));
                    //    }

                    //    if (Passed)
                    //    {
                    //        //創建連接對象
                    //        User = new UserSocket();
                    //        User.ID = UserID;
                    //        User.Socket = newClient;
                    //        User.State = UserSocket.UserStates.Online;

                    //        using (SQLHelper conn = new SQLHelper(DBInfo))
                    //        {
                    //            conn.OpenConnection();
                    //            try
                    //            {
                    //                #region " 獲得當前用記的所有聯絡人并向他們推送用戶上線消息 "

                    //                StateNotifyQueue.Enqueue(new List<object>() { User, "1" });

                    //                //DataTable ContactsList = GetContacts(conn, UserID);
                    //                //if (ContactsList.Rows.Count > 0)
                    //                //{
                    //                //    foreach (DataRow Contact in ContactsList.Rows)
                    //                //    {
                    //                //        //加入聯絡人(防呆自己加自己)
                    //                //        if (User.ID != Contact["contact_id"].ToString())
                    //                //            User.Contacts.Add(Contact["contact_id"].ToString());
                    //                //    }
                    //                //    //改為獨立線程來發
                    //                //    //如果此聯絡人在線就通知他(她)當前用戶上線了
                    //                //    //try
                    //                //    //{
                    //                //    //    Thread stateThread = new Thread(new ParameterizedThreadStart(StateNotifyThreadFunc));
                    //                //    //    stateThread.Start(User);
                    //                //    //}
                    //                //    //catch
                    //                //    //{ }
                    //                //    //如果此聯絡人在線就通知他(她)當前用戶上線了
                    //                //    SendUserState(User);
                    //                //}
                    //                //ContactsList.Dispose();
                    //                //ContactsList = null;

                    //                #endregion

                    //                #region " 發送所有未讀訊息(手機版暫時不推未讀取消息) "

                    //                //DataTable MsgsList = GetUnreadMsgs(conn, UserID);
                    //                //if (MsgsList.Rows.Count > 0)
                    //                //{
                    //                //    if (newClient != null)
                    //                //    {
                    //                //        foreach (DataRow UnreadMsg in MsgsList.Rows)
                    //                //        {
                    //                //            // 發給登錄人
                    //                //            DateTime MsgDT = DateTime.Parse(UnreadMsg["msg_date"].ToString() + " " + UnreadMsg["msg_time"].ToString());
                    //                //            byte[] rtnMsg = WebConvertMethod.ConvertMsgToByte(UnreadMsg["msg_text"].ToString(),
                    //                //                                                              UnreadMsg["td_no"].ToString().Length > 0 ? "4" : "U",
                    //                //                                                              UnreadMsg["msg_from"].ToString(),
                    //                //                                                              UnreadMsg["user_name"].ToString(),
                    //                //                                                              UnreadMsg["td_no"].ToString(),
                    //                //                                                              MsgDT,
                    //                //                                                              UnreadMsg["msg_guid"].ToString());
                    //                //            lock (newClient)
                    //                //            {
                    //                //                newClient.Send(rtnMsg);
                    //                //            }
                    //                //        }

                    //                //        // 更新為已讀 
                    //                //        conn.ExecuteSQL("update a set a.msg_state='1' from lrmsgstate a where a.msg_to='" + UserID + "' and a.msg_state='0'");
                    //                //    }
                    //                //}
                    //                //MsgsList.Dispose();
                    //                //MsgsList = null;

                    //                #endregion
                    //            }
                    //            catch (SocketException ex)
                    //            {
                    //                //test
                    //                //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "向PC端" + DataTerminal + "推送未讀信息時出錯." + (ex != null ? ex.Message : ""));
                    //                LogHelper.WriteLog("StartUp()", "向Mobile端" + DataTerminal + "推送未讀信息時出錯." + (ex != null ? ex.Message : ""));
                    //            }

                    //            try
                    //            {
                    //                //更新用戶狀態
                    //                DoUpdateUserLog(conn, UserID, "0", "1", "登錄");
                    //                DoUpdateUserState(conn, UserID, "1"); //上線中
                    //            }
                    //            catch (Exception ex)
                    //            {
                    //                Passed = false;
                    //                LogHelper.WriteLog("StartUp()", "更新Mobile端用戶:" + DataTerminal + "狀態." + (ex != null ? ex.Message : ""));
                    //            }
                    //            conn.CloseConnection();
                    //        }

                    //        if (Passed)
                    //        {
                    //            // 將新連接加入轉發表並創建線程為其服務
                    //            lock (_ws_transmit_tb.SyncRoot)
                    //            {
                    //                //_ws_transmit_tb.Add(UserID, newClient);
                    //                _ws_transmit_tb.Add(UserID, User);
                    //            }
                    //            //LogHelper.WriteLog("StartUp()", "手機端" + DataTerminal + "已添加到在線用戶列表");

                    //            try
                    //            {
                    //                Thread clientThread = new Thread(new ParameterizedThreadStart(WebThreadFunc));
                    //                //加入哈希表
                    //                _ws_thread_tb.Add(UserID, clientThread);
                    //                //clientThread.Start(userName);
                    //                clientThread.Start(UserID);
                    //                //LogHelper.WriteLog("StartUp()", "手機端" + DataTerminal + "-" + DataTerminalName + "登錄成功");
                    //            }
                    //            catch (Exception ex)
                    //            {
                    //                try
                    //                {
                    //                    // 發生錯誤時移除連接
                    //                    lock (_ws_transmit_tb.SyncRoot)
                    //                    {
                    //                        //_transmit_tb.Add(UserID, newClient);
                    //                        _ws_transmit_tb.Remove(UserID);
                    //                    }
                    //                }
                    //                catch
                    //                { }
                    //                //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():開啟新線程", "建立登入用戶新線程時:" + ex.Message);
                    //                LogHelper.WriteLog("StartUp()", "建立登入用戶" + DataTerminal + "-" + DataTerminalName + "新線程時:" + (ex != null ? ex.Message : ""));
                    //            }
                    //        }
                    //    }
                    //}
                    //需不需要干掉自己?
                    //Thread.CurrentThread.Abort();
                    #endregion

                    LogHelper.WriteLog("ProcessLogin", "暫不支持Web客戶端登錄");
                    Done = false;
                }
                else
                {
                    // 無效訊息-丟棄
                    Done = false;
                    try
                    {
                        LogHelper.WriteLog("ProcessLogin", "無效請求數據:" + Encoding.UTF8.GetString(userToken.ReceiveEventArgs.Buffer));
                    }
                    catch
                    { }
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("ProcessLogin", "登錄時出現問題:" + (ex != null ? ex.Message : ""));
                Done = false;
            }
            finally
            {
                //結束計時
                sw.Stop();
                //收集監視器數據之登錄統計結束
                ServerStatistics.LoginStatEnd(sw.ElapsedMilliseconds);
            }
            //添加到正在執行的列表中
            //m_pcSocketUserTokenList.Add(DataTerminal, userToken);

            return Done;
        }
Ejemplo n.º 6
0
        /// <summary>
        /// 關閉客戶端連接
        /// </summary>
        /// <param name="userToken"></param>
        public void CloseClientSocket(SocketUserToken userToken, bool ProcessUserDisconnected)
        {
            if (userToken == null)
                return;
            lock (userToken)
            {
                //說明這個客戶端Token已經牌關閉狀態了,其他的不要進來.
                //這里主要是給客戶端主動斷開連接引起的userToken.ReceiveEventArgs.BytesTransferred == 0解發時進入
                if (!userToken.Closing)
                    userToken.Closing = true;
                else
                    return;

                string curDevice = "客戶端", RemoteEndPoint = "";

                try
                {
                    //處理用戶斷開之後的作業(語音通話會用到)
                    if (ProcessUserDisconnected)
                        userToken.Processor.ProcessUserDisconnected();

                    //處理當前用戶離線狀態的通知
                    if (userToken != null && userToken.BindingUser != null)
                        if (userToken.BindingUser.Role == User.UserRole.PC || userToken.BindingUser.Role == User.UserRole.Mobile)
                            ProcessUserOfflineState(userToken);

                    if (userToken == null)
                        return;
                    if (userToken.ConnectSocket == null)
                        return;
                    RemoteEndPoint = userToken.ConnectSocket.RemoteEndPoint.ToString();
                }
                catch
                {
                    LogHelper.WriteLog("CloseClientSocket", "Part 1");
                }
                try
                {
                    if (userToken.ConnectSocket.Connected)
                        userToken.ConnectSocket.Shutdown(SocketShutdown.Both);
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLog("CloseClientSocket", string.Format("斷開與客戶端: [{0}] 的連接時出錯:{1}.", userToken.BindingUser.ID + "[" + userToken.ConnectSocket.RemoteEndPoint + "]", (ex != null ? ex.Message : "")));
                }
                try
                {
                    //如果在S通道里斷開T連接,執行到這句時T連接會觸發CloseClientSocket()方法.所以要lock下,保證本次執行完成再執行T通道的方法.
                    //否則會打架.
                    userToken.ConnectSocket.Close();

                    //釋放引用,并清理緩存等資源
                    userToken.ConnectSocket = null;
                    m_maxNumberAcceptedClients.Release();
                    m_idleUserTokenPool.Push(userToken);
                }
                catch
                {
                    LogHelper.WriteLog("CloseClientSocket", "Part 2");
                }


                try
                {
                    if (userToken.BindingUser != null)
                    {
                        switch (userToken.BindingUser.Role)
                        {
                            case User.UserRole.PC:
                                curDevice = "PC客戶端";
                                m_pcUserTokenList.Remove(userToken);
                                break;
                            case User.UserRole.Mobile:
                                curDevice = "Mobile客戶端";
                                m_mobileUserTokenList.Remove(userToken);
                                break;
                            case User.UserRole.FileTransfer:
                                curDevice = "文件傳送客戶端";
                                m_fileUserTokenList.Remove(userToken);
                                break;
                            case User.UserRole.APP:
                                curDevice = "APP服務端";
                                m_appUserTokenList.Remove(userToken);
                                break;
                            case User.UserRole.SubService:
                                curDevice = "訂閱號服務端";
                                m_subServiceTokenList.Remove(userToken);
                                break;
                            case User.UserRole.AudioCall:
                                curDevice = "語音通話客戶端";
                                m_audioCallTokenList.Remove(userToken);
                                break;
                        }
                    }
                }
                catch
                {
                    LogHelper.WriteLog("CloseClientSocket", "Part 3");
                }
                //@<" + userToken.BindingUser.ID + " " + userToken.ConnectSocket.RemoteEndPoint + "> "
                LogHelper.WriteLog("CloseClientSocket", string.Format("斷開與{1}: {0}的連接.", "@<" + userToken.BindingUser.ID + " " + RemoteEndPoint + "> ", curDevice));
                try
                {
                    //這個只能放最後,否則前面的userToken.User.ID為空
                    ResetUserToken(userToken);
                }
                catch
                {
                    LogHelper.WriteLog("CloseClientSocket", "Part 4");
                }
            }
        }
Ejemplo n.º 7
0
        private static void ResetUserToken(SocketUserToken userToken)
        {
            userToken.Processor = null;
            //userToken.ReceiveQueue.Clear();
            //userToken.RestPacketLength = 0;
            userToken.FirstPacket = true;

            userToken.ReceiveBuffer.Clear();

            //如果緩衝區超過64KB,則回收它重新分配為4KB,以節省系統內存資源.
            if (userToken.ReceiveBuffer.Buffer.Length > ServerConst.MaxBufferSize)
                userToken.ReceiveBuffer = new DynamicBufferManager(ServerConst.InitBufferSize);

            userToken.BindingUser = null;
            userToken.Closing = false;
            userToken.AsyncSendAgent = null;
        }
Ejemplo n.º 8
0
        /// <summary>
        /// 處理當前用戶離線狀態的通知
        /// </summary>
        /// <param name="userToken"></param>
        private void ProcessUserOfflineState(SocketUserToken userToken)
        {
            if (userToken == null || userToken.BindingUser == null)
                return;
            User curUser = userToken.BindingUser;

            try
            {
                //判斷用戶有沒登錄成功,有就通知聯絡人用戶狀態變更q
                if (m_pcUserTokenList.ContainsKey(curUser.ID))
                {
                    //目前只寫對PC端用戶,應該還要考慮其他用戶
                    //通知在線的聯絡人當前用戶改變了狀態
                    curUser.SetUserState("6");
                    using (SQLHelper conn = new SQLHelper(DBInfo))
                    {
                        conn.OpenConnection();
                        try
                        {
                            DoUpdateUserLog(conn, curUser.ID, "1", ((int)curUser.Mobile).ToString(), "客戶端登出", ((IPEndPoint)userToken.ConnectSocket.RemoteEndPoint).Address.ToString(), "", "", null);
                            //如果手機端沒在線就通知聯絡人此人離線了
                            SocketUserToken MobileUser = m_mobileUserTokenList[curUser.ID] as SocketUserToken;
                            if (MobileUser == null)
                            {
                                //StateNotifyQueue.Enqueue(new List<object>() { userToken, ((int)curUser.State).ToString() });
                                //ID,狀態,簽名,聯絡人清單,頭像數據
                                if (curUser.Contacts.Count > 0)
                                    StateNotifyQueue.Enqueue(new List<object>() { curUser.ID, ((int)curUser.State).ToString(), curUser.Signature, curUser.Contacts, null });

                                DoUpdateUserState(conn, curUser.ID, "6"); //離線
                            }
                            conn.CloseConnection();
                        }
                        catch
                        {
                            conn.CloseConnection();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("ProcessUserOfflineState", "通知聯絡人用戶:" + curUser.ID + "離線時出錯:" + (ex != null ? ex.Message : ""));
            }

            ////通知在線的聯絡人當前用戶改變了狀態
            //curUser.SetUserState("6");
            //using (SQLHelper conn = new SQLHelper(DBInfo))
            //{
            //    conn.OpenConnection();
            //    try
            //    {
            //        DoUpdateUserLog(conn, curUser.ID, "1", "0", "PC端登出");
            //        //如果手機端沒在線就通知聯絡人此人離線了
            //        UserSocket WebUser = _ws_transmit_tb[curUser.ID] as UserSocket;
            //        if (WebUser == null)
            //        {
            //            WebUser = _mobile_transmit_tb[curUser.ID] as UserSocket;
            //            if (WebUser == null)
            //            {
            //                StateNotifyQueue.Enqueue(new List<object>() { curUser, ((int)curUser.State).ToString() });
            //                DoUpdateUserState(conn, curUser.ID, "6"); //離線
            //            }
            //        }
            //        conn.CloseConnection();
            //    }
            //    catch
            //    {
            //        conn.CloseConnection();
            //    }
            //}
        }
Ejemplo n.º 9
0
 public void CloseClientSocket(SocketUserToken userToken)
 {
     CloseClientSocket(userToken, true);
 }
Ejemplo n.º 10
0
        /// <summary>
        /// 訂閱號服務端登錄
        /// </summary>
        /// <param name="UserID"></param>
        /// <param name="DataTerminalName"></param>
        /// <param name="DataGroup"></param>
        /// <param name="DataText"></param>
        /// <param name="userToken"></param>
        /// <param name="UserTokenList"></param>
        /// <returns></returns>
        private bool DoSubServiceLogin(string UserID, string DataTerminalName, string DataGroup, string DataText, SocketUserToken userToken, SocketUserTokenList UserTokenList)
        {
            bool Passed = true, Done = false;
            SocketUserToken ExistsUser = UserTokenList["#" + UserID + "#"];
            if (ExistsUser != null)
            {
                Socket curSkt = ExistsUser.ConnectSocket;
                string curIPAddress = ExistsUser.ConnectSocket.RemoteEndPoint.ToString();
                #region " 發送離線 "

                try
                {
                    List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("00", "7", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), "");
                    //如果2秒內得不到之前登陸的對象,就直接干掉
                    //否則此帳號將永遠無法登錄
                    if (Monitor.TryEnter(curSkt, 2000))
                    {
                        try
                        {
                            //向用戶本人發送離線
                            foreach (byte[] msg in msgs)
                            {
                                //2016/05/19 test
                                ExistsUser.AsyncSendAgent.DoSendBuffer(msg);
                                //curSkt.Send(msg);
                                //SendData(curSkt, msg);
                            }
                        }
                        catch (SocketException ex)
                        {
                            LogHelper.WriteLog("DoSubServiceLogin()", "執行向" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 發送強制離線[不允許自動重連]消息時:" + (ex != null ? ex.Message : ""));
                        }
                        finally
                        {
                            Monitor.Exit(curSkt);
                        }
                    }
                    else
                    {
                        //如果到這里說明之前登陸的對象已經死鎖  
                        LogHelper.WriteLog("DoSubServiceLogin()", "嘗試使用Monitor.TryEnter鎖定" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 時失敗.");
                    }
                }
                catch (SocketException ex)
                {
                    LogHelper.WriteLog("DoSubServiceLogin()", "向" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 發送離線[不允許自動重連]消息時:" + (ex != null ? ex.Message : ""));
                }

                try
                {
                    //運行到這里時,有可能客戶端收到7-00之後主動斷開連接,則會觸發CloseClientSocket.
                    if (!ExistsUser.Closing)
                    {
                        //ExistsUser.Closing = true;
                        CloseClientSocket(ExistsUser);
                    }

                    LogHelper.WriteLog("DoSubServiceLogin", string.Format("因相同帳號再次登錄,強制先登錄的用戶{0} [{1}] 下線.", UserID, curIPAddress));

                    UpdateUserLog(UserID, "1", "0", "因相同帳號再次登陸而強制離線.", "", null);
                }
                catch (SocketException ex)
                {
                    LogHelper.WriteLog("DoSubServiceLogin()", "嘗試關閉" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 線程和Socket連接時出錯." + (ex != null ? ex.Message : ""));
                }

                #endregion
            }
            // 驗證是否為唯一用戶
            if (UserTokenList.ContainsKey("#" + UserID + "#"))
            {
                //到這里說明前面強制離線沒有成功
                try
                {
                    List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("登錄失敗.", "3", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), "");
                    //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                    lock (userToken.ConnectSocket)
                    {
                        foreach (byte[] msg in msgs)
                        {
                            //同步發送
                            //2016/05/19 test
                            userToken.AsyncSendAgent.DoSendBuffer(msg);
                            //userToken.ConnectSocket.Send(msg);
                            //SendData(userToken.ConnectSocket, msg);
                        }
                    }
                    LogHelper.WriteLog("DoSubServiceLogin()", DataGroup + "用戶:" + UserID + "登錄失敗");
                }
                catch (SocketException ex)
                {
                    LogHelper.WriteLog("DoSubServiceLogin()", "發送登陸失敗信息時" + (ex != null ? ex.Message : ""));
                }
            }
            else
            {
                // 服務器開放登錄功能
                try
                {
                    List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, DataGroup, Guid.NewGuid().ToString().Replace("-", "").ToUpper(), "");
                    //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                    lock (userToken.ConnectSocket)
                    {
                        foreach (byte[] msg in msgs)
                        {
                            //2016/05/19 test
                            userToken.AsyncSendAgent.DoSendBuffer(msg);
                            //userToken.ConnectSocket.Send(msg);
                            //SendData(userToken.ConnectSocket, msg);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Passed = false;
                    LogHelper.WriteLog("DoSubServiceLogin()", "發送登錄成功信息時" + (ex != null ? ex.Message : ""));
                }

                if (Passed)
                {
                    //設置對象狀態
                    userToken.BindingUser = new User();
                    userToken.BindingUser.State = User.UserStates.Online;
                    userToken.BindingUser.Role = User.UserRole.SubService;
                    userToken.BindingUser.Mobile = User.UserMobileType.None;
                    userToken.BindingUser.ID = UserID;
                    //Mac
                    userToken.BindingUser.MacAddr = DataTerminalName;

                    if (Passed)
                    {
                        //添加到正在執行的列表中
                        if (UserTokenList.ContainsKey("#" + UserID + "#"))
                        {
                            ExistsUser = UserTokenList["#" + UserID + "#"];
                            if (ExistsUser != null)
                            {
                                try
                                {
                                    LogHelper.WriteLog("DoSubServiceLogin", string.Format("加入在線人員列表時發現已有同名帳號在里面,強制用戶{0} [{1}] 下線.", UserID, ExistsUser.ConnectSocket.RemoteEndPoint));

                                    if (!ExistsUser.Closing)
                                    {
                                        //ExistsUser.Closing = true;
                                        CloseClientSocket(ExistsUser);
                                    }
                                }
                                catch (SocketException ex)
                                {
                                    LogHelper.WriteLog("DoSubServiceLogin()", "嘗試關閉" + DataGroup + "用戶" + UserID + "線程和Socket連接時出錯." + (ex != null ? ex.Message : ""));
                                }
                            }
                            //LogHelper.WriteLog("ProcessLogin()", "#5.加入在線人員列表時發現已有同名帳號在里面. " + UserID + " [" + userToken.ConnectSocket.RemoteEndPoint + "]");
                        }
                        UserTokenList.Add("#" + UserID + "#", userToken);
                        //取消日志
                        //LogHelper.WriteLog("ProcessLogin()", "#6.已加入到在線人員列表. " + UserID + " [" + userToken.ConnectSocket.RemoteEndPoint + "]");
                        //System.Diagnostics.Debug.WriteLine(UserID + " Logged in at " + DateTime.Now.ToString("HH:mm:ss:fff"));
                        Done = true;
                    }
                }
            }
            return Done;
        }
Ejemplo n.º 11
0
        private bool DoPcMobileLogin(string UserID, string DataTerminalName, string DataGroup, string DataText, SocketUserToken userToken, SocketUserTokenList UserTokenList)
        {
            bool Passed = true, Done = false;
            SocketUserToken ExistsUser = UserTokenList[UserID];
            if (ExistsUser != null)
            {
                Socket curSkt = ExistsUser.ConnectSocket;
                string curIPAddress = ExistsUser.ConnectSocket.RemoteEndPoint.ToString();
                #region " 發送離線 "

                try
                {
                    List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("00", "7", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), "");
                    //如果2秒內得不到之前登陸的對象,就直接干掉
                    //否則此帳號將永遠無法登錄
                    if (Monitor.TryEnter(curSkt, 2000))
                    {
                        try
                        {
                            //向用戶本人發送離線
                            foreach (byte[] msg in msgs)
                            {
                                //2016/05/19 test
                                ExistsUser.AsyncSendAgent.DoSendBuffer(msg);
                                //curSkt.Send(msg);
                                //SendData(curSkt, msg);
                            }
                        }
                        catch (SocketException ex)
                        {
                            LogHelper.WriteLog("DoPcMobileLogin()", "執行向" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 發送強制離線[不允許自動重連]消息時:" + (ex != null ? ex.Message : ""));
                        }
                        finally
                        {
                            Monitor.Exit(curSkt);
                        }
                    }
                    else
                    {
                        //如果到這里說明之前登陸的對象已經死鎖  
                        LogHelper.WriteLog("DoPcMobileLogin()", "嘗試使用Monitor.TryEnter鎖定" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 時失敗.");
                    }
                }
                catch (SocketException ex)
                {
                    LogHelper.WriteLog("DoPcMobileLogin()", "向" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 發送離線[不允許自動重連]消息時:" + (ex != null ? ex.Message : ""));
                }

                try
                {
                    //運行到這里時,有可能客戶端收到7-00之後主動斷開連接,則會觸發CloseClientSocket.
                    if (!ExistsUser.Closing)
                    {
                        //ExistsUser.Closing = true;
                        CloseClientSocket(ExistsUser);
                    }

                    LogHelper.WriteLog("DoPcMobileLogin", string.Format("因相同帳號再次登錄,強制先登錄的用戶{0} [{1}] 下線.", UserID, curIPAddress));

                    UpdateUserLog(UserID, "1", "0", "因相同帳號再次登陸而強制離線.", "", null);
                }
                catch (SocketException ex)
                {
                    LogHelper.WriteLog("DoPcMobileLogin()", "嘗試關閉" + DataGroup + "用戶: " + UserID + " [" + curIPAddress + "] 線程和Socket連接時出錯." + (ex != null ? ex.Message : ""));
                }

                #endregion
            }
            // 驗證是否為唯一用戶
            if (UserTokenList.ContainsKey(UserID))
            {
                //到這里說明前面強制離線沒有成功
                try
                {
                    List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("登錄失敗.", "3", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), "");
                    //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                    lock (userToken.ConnectSocket)
                    {
                        foreach (byte[] msg in msgs)
                        {
                            //同步發送
                            //2016/05/19 test
                            userToken.AsyncSendAgent.DoSendBuffer(msg);
                            //userToken.ConnectSocket.Send(msg);
                            //SendData(userToken.ConnectSocket, msg);
                        }
                    }
                    LogHelper.WriteLog("ProcessLogin()", DataGroup + "用戶:" + UserID + "登錄失敗");
                }
                catch (SocketException ex)
                {
                    LogHelper.WriteLog("ProcessLogin()", "發送登陸失敗信息時" + (ex != null ? ex.Message : ""));
                }
            }
            else
            {
                // 服務器開放登錄功能
                try
                {
                    List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, DataGroup, Guid.NewGuid().ToString().Replace("-", "").ToUpper(), "");
                    //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                    lock (userToken.ConnectSocket)
                    {
                        foreach (byte[] msg in msgs)
                        {
                            //2016/05/19 test
                            userToken.AsyncSendAgent.DoSendBuffer(msg);
                            //userToken.ConnectSocket.Send(msg);
                            //SendData(userToken.ConnectSocket, msg);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Passed = false;
                    LogHelper.WriteLog("ProcessLogin()", "發送登錄成功信息時" + (ex != null ? ex.Message : ""));
                }

                if (Passed)
                {
                    //設置對象狀態
                    userToken.BindingUser = new User();
                    userToken.BindingUser.State = User.UserStates.Online;
                    userToken.BindingUser.Role = (DataGroup.Length > 0 ? User.UserRole.Mobile : User.UserRole.PC);
                    //移動設備登錄為: 
                    //iPhone = "IPHONE"
                    //iPad = "IPAD"
                    //Android Phone = "APHONE"
                    //Android Pad = "APAD"
                    switch (DataGroup.ToUpper())
                    {
                        case "IPHONE":
                            userToken.BindingUser.Mobile = User.UserMobileType.iPhone;
                            //iToken
                            userToken.BindingUser.iToken = DataText;
                            break;
                        case "IPAD":
                            userToken.BindingUser.Mobile = User.UserMobileType.iPad;
                            //iToken
                            userToken.BindingUser.iToken = DataText;
                            break;
                        case "APHONE":
                            userToken.BindingUser.Mobile = User.UserMobileType.AndroidPhone;
                            break;
                        case "APAD":
                            userToken.BindingUser.Mobile = User.UserMobileType.AndroidPad;
                            break;
                        default:
                            //默認PC
                            userToken.BindingUser.Mobile = User.UserMobileType.None;
                            break;
                    }
                    userToken.BindingUser.ID = UserID;
                    //Mac
                    userToken.BindingUser.MacAddr = DataTerminalName;
                    //IP
                    userToken.BindingUser.IP = ((IPEndPoint)userToken.ConnectSocket.RemoteEndPoint).Address.ToString();
                    //設備名稱
                    userToken.BindingUser.DevName = DataText;
                    Socket newClient = userToken.ConnectSocket;

                    string UserRegion = "";

                    using (SQLHelper conn = new SQLHelper(DBInfo))
                    {
                        conn.OpenConnection();
                        try
                        {
                            //取消日誌
                            //LogHelper.WriteLog("ProcessLogin()", "#5.登錄成功,準備截入聯絡人信息及推送未讀消息. " + UserID + " [" + userToken.ConnectSocket.RemoteEndPoint + "]");

                            #region " 載入聯絡人清單(聯絡人變更時應更新) "

                            DataTable ContactsList = GetContacts(conn, UserID);
                            if (ContactsList.Rows.Count > 0)
                            {
                                foreach (DataRow Contact in ContactsList.Rows)
                                {
                                    //加入聯絡人(防呆自己加自己)
                                    if (UserID != Contact["contact_id"].ToString())
                                        userToken.BindingUser.Contacts.Add(Contact["contact_id"].ToString());
                                }
                            }
                            ContactsList = null;

                            #endregion

                            #region " 當PC端和Mobile端未登錄的情況下才向其聯絡人推送用戶上線消息 "

                            if (!m_pcUserTokenList.ContainsKey(UserID) && !m_mobileUserTokenList.ContainsKey(UserID))
                                //ID,狀態,簽名,聯絡人清單,頭像數據
                                if (userToken.BindingUser.Contacts.Count > 0)
                                    StateNotifyQueue.Enqueue(new List<object>() { userToken.BindingUser.ID, "1", userToken.BindingUser.Signature, userToken.BindingUser.Contacts, null });

                            #endregion

                            #region " 發送所有未讀訊息和群命令 "

                            #region " 訊息 "

                            DataTable MsgsList = GetUnreadMsgs(conn, UserID, "M");
                            if (MsgsList.Rows.Count > 0)
                            {
                                if (newClient != null)
                                {
                                    if (MsgsList.Rows.Count > 0)
                                    {
                                        long MaxMsgNO = 0;
                                        foreach (DataRow UnreadMsg in MsgsList.Rows)
                                        {
                                            // 記錄最大MsgNO
                                            if (MaxMsgNO < long.Parse(UnreadMsg["msg_no"].ToString()))
                                                MaxMsgNO = long.Parse(UnreadMsg["msg_no"].ToString());

                                            // 發給登錄人
                                            DateTime MsgDT = DateTime.Parse(UnreadMsg["msg_date"].ToString() + " " + UnreadMsg["msg_time"].ToString());
                                            // 判斷個人消息還是群消息
                                            // 消息子類型(msg_doctype)(文字消息/文件消息) 
                                            // 0 = File 
                                            // 1 = Text Msg 
                                            // 2 = offline File
                                            // 3 = 截圖
                                            // 4 = email 
                                            // 5 = 抖動
                                            // 6 = 音頻
                                            List<byte[]> rtnMsgs = null;
                                            switch (UnreadMsg["msg_doctype"].ToString())
                                            {
                                                case "0":
                                                    rtnMsgs = ParseProtocol.ConvertMsgToByte(UnreadMsg["msg_text"].ToString(),
                                                                "P",
                                                                UnreadMsg["msg_from"].ToString(),
                                                                UnreadMsg["user_name"].ToString(),
                                                                "S",
                                                                MsgDT,
                                                                UnreadMsg["msg_guid"].ToString(),
                                                                UnreadMsg["msg_no"].ToString(),
                                                                      "");
                                                    break;
                                                case "2":
                                                    rtnMsgs = ParseProtocol.ConvertMsgToByte(UnreadMsg["msg_text"].ToString(),
                                                                "P",
                                                                UnreadMsg["msg_from"].ToString(),
                                                                UnreadMsg["user_name"].ToString(),
                                                                "O",
                                                                MsgDT,
                                                                UnreadMsg["msg_guid"].ToString(),
                                                                UnreadMsg["msg_no"].ToString(),
                                                                      "");
                                                    break;
                                                case "3":
                                                    rtnMsgs = ParseProtocol.ConvertMsgToByte((byte[])UnreadMsg["msg_img"],
                                                                "I",
                                                                UnreadMsg["msg_from"].ToString(),
                                                                UnreadMsg["user_name"].ToString(),
                                                                UnreadMsg["td_no"].ToString(),
                                                                MsgDT,
                                                                UnreadMsg["msg_guid"].ToString(),
                                                                UnreadMsg["msg_no"].ToString(),
                                                                      "");
                                                    break;
                                                case "4":
                                                    rtnMsgs = ParseProtocol.ConvertMsgToByte(UnreadMsg["msg_text"].ToString(),
                                                                "M",
                                                                UnreadMsg["msg_from"].ToString(),
                                                                UnreadMsg["user_name"].ToString(),
                                                                UnreadMsg["td_no"].ToString(),
                                                                MsgDT,
                                                                UnreadMsg["msg_guid"].ToString(),
                                                                UnreadMsg["msg_no"].ToString(),
                                                                      "");
                                                    break;
                                                case "5":
                                                    rtnMsgs = ParseProtocol.ConvertMsgToByte(UnreadMsg["msg_text"].ToString(),
                                                                "Q",
                                                                UnreadMsg["msg_from"].ToString(),
                                                                UnreadMsg["user_name"].ToString(),
                                                                UnreadMsg["td_no"].ToString(),
                                                                MsgDT,
                                                                UnreadMsg["msg_guid"].ToString(),
                                                                UnreadMsg["msg_no"].ToString(),
                                                                      "");
                                                    break;
                                                case "6":
                                                    rtnMsgs = ParseProtocol.ConvertMsgToByte("Voice",
                                                                "R",
                                                                UnreadMsg["msg_from"].ToString(),
                                                                UnreadMsg["user_name"].ToString(),
                                                                UnreadMsg["td_no"].ToString(),
                                                                MsgDT,
                                                                UnreadMsg["msg_guid"].ToString(),
                                                                UnreadMsg["msg_no"].ToString(),
                                                                      "");
                                                    break;
                                                default:
                                                    //1
                                                    string DataType = "";
                                                    if (UnreadMsg["msg_type"].ToString() == "0")
                                                    {
                                                        //小助手系統消息
                                                        DataType = "5";
                                                    }
                                                    else
                                                    {
                                                        DataType = UnreadMsg["td_no"].ToString().Length > 0 ? "4" : (UnreadMsg["msg_doctype"].ToString() == "0" ? "P" : "U");
                                                    }
                                                    rtnMsgs = ParseProtocol.ConvertMsgToByte(UnreadMsg["msg_text"].ToString(),
                                                                DataType,
                                                                UnreadMsg["msg_from"].ToString(),
                                                                UnreadMsg["user_name"].ToString(),
                                                                UnreadMsg["td_no"].ToString(),
                                                                MsgDT,
                                                                UnreadMsg["msg_guid"].ToString(),
                                                                UnreadMsg["msg_no"].ToString(),
                                                                        "");
                                                    break;
                                            }
                                            //if (UnreadMsg["msg_doctype"].ToString() == "3")
                                            //{
                                            //    rtnMsgs = ParseProtocol.ConvertMsgToByte((byte[])UnreadMsg["msg_img"],
                                            //                                            "I",
                                            //                                            UnreadMsg["msg_from"].ToString(),
                                            //                                            UnreadMsg["user_name"].ToString(),
                                            //                                            UnreadMsg["td_no"].ToString(),
                                            //                                            MsgDT,
                                            //                                            UnreadMsg["msg_guid"].ToString(),
                                            //                                            UnreadMsg["msg_no"].ToString(),
                                            //                                                  "");
                                            //}
                                            //else
                                            //{
                                            //    rtnMsgs = ParseProtocol.ConvertMsgToByte(UnreadMsg["msg_text"].ToString(),
                                            //        UnreadMsg["td_no"].ToString().Length > 0 ? "4" : (UnreadMsg["msg_doctype"].ToString() == "0" ? "P" : "U"),
                                            //                                                    UnreadMsg["msg_from"].ToString(),
                                            //                                                    UnreadMsg["user_name"].ToString(),
                                            //                                                    UnreadMsg["td_no"].ToString(),
                                            //                                                    MsgDT,
                                            //                                                    UnreadMsg["msg_guid"].ToString(),
                                            //                                                    UnreadMsg["msg_no"].ToString(),
                                            //                                                          "");
                                            //}
                                            //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                                            lock (newClient)
                                            {
                                                foreach (byte[] msg in rtnMsgs)
                                                {
                                                    //2016/05/19 test
                                                    userToken.AsyncSendAgent.DoSendBuffer(msg);
                                                    //newClient.Send(msg);
                                                    //SendData(newClient, msg);
                                                }
                                            }
                                        }

                                        // 更新為已讀 
                                        try
                                        {
                                            MarkReadHistoryMsgQueue.Enqueue("update a set a.msg_state='1' from lrmsgstate a where a.msg_no<=" + MaxMsgNO.ToString() + " and a.msg_to='" + UserID + "' and a.msg_state='0'");
                                        }
                                        catch (Exception ex)
                                        {
                                            LogHelper.WriteLog("ProcessLogin()", "標識歷史信息為已讀時:" + (ex != null ? ex.Message : ""));
                                        }
                                    }
                                }
                                //Test
                                LogHelper.WriteLog("ProcessLogin()", "共向" + DataGroup + "用戶:" + userToken.BindingUser.ID + "推送" + MsgsList.Rows.Count.ToString() + "條歷史未讀消息.");
                            }

                            #endregion

                            #region " 系統消息 "

                            MsgsList = GetUnreadMsgs(conn, UserID, "S");
                            if (MsgsList.Rows.Count > 0)
                            {
                                if (newClient != null)
                                {
                                    if (MsgsList.Rows.Count > 0)
                                    {
                                        long MaxMsgNO = 0;
                                        foreach (DataRow UnreadMsg in MsgsList.Rows)
                                        {
                                            // 記錄最大MsgNO
                                            if (MaxMsgNO < long.Parse(UnreadMsg["sys_id"].ToString()))
                                                MaxMsgNO = long.Parse(UnreadMsg["sys_id"].ToString());

                                            // 發給登錄人
                                            DateTime MsgDT = DateTime.Parse(UnreadMsg["sys_date"].ToString() + " " + UnreadMsg["sys_time"].ToString());
                                            // 判斷個人消息還是群消息
                                            List<byte[]> rtnMsgs = ParseProtocol.ConvertMsgToByte(UnreadMsg["sys_remk"].ToString(),
                                                                                                  UnreadMsg["sys_type"].ToString() == "1" ? "D" : "*",
                                                                                                  UnreadMsg["sys_type"].ToString(),
                                                                                                  UnreadMsg["sys_objtype"].ToString(),
                                                                                                  "*",
                                                                                                  MsgDT,
                                                                                                  UnreadMsg["sys_objid"].ToString(),
                                                                                                  UnreadMsg["sys_id"].ToString(),
                                                                                                  "");
                                            //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                                            lock (newClient)
                                            {
                                                foreach (byte[] msg in rtnMsgs)
                                                {
                                                    //2016/05/19 test
                                                    userToken.AsyncSendAgent.DoSendBuffer(msg);
                                                    //newClient.Send(msg);
                                                    //SendData(newClient, msg);
                                                }
                                            }
                                        }

                                        // 更新為已讀 
                                        try
                                        {
                                            MarkReadHistoryMsgQueue.Enqueue("update a set a.sysmsg_state='1' from lrsysmsgstate a where a.sys_id<=" + MaxMsgNO.ToString() + " and a.sysmsg_to='" + UserID + "' and a.sysmsg_state='0'");
                                            //conn.ExecuteSQL("update a set a.msg_state='1' from lrmsgstate a where a.msg_no<=" + MaxMsgNO.ToString() + " and a.msg_to='" + UserID + "' and a.msg_state='0'");
                                        }
                                        catch (Exception ex)
                                        {
                                            LogHelper.WriteLog("ProcessLogin()", "標識歷史系統消息為已讀時:" + (ex != null ? ex.Message : ""));
                                        }
                                    }
                                }
                                //Test
                                //LogHelper.WriteLog("ProcessLogin()", "共向用戶:" + User.ID + "推送" + MsgsList.Rows.Count.ToString() + "條歷史命令.");
                            }

                            #endregion

                            MsgsList.Dispose();
                            MsgsList = null;

                            #endregion

                            //得到用戶區域代號
                            try
                            {
                                UserRegion = conn.OpenDataTable("select user_region from lrtduser (nolock) where user_no='" + UserID + "'", CommandType.Text).Rows[0][0].ToString();
                            }
                            catch
                            {
                                UserRegion = "";
                            }
                        }
                        catch (SocketException ex)
                        {
                            //test
                            //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "向PC端" + DataTerminal + "推送未讀信息時出錯." + (ex != null ? ex.Message : ""));
                            LogHelper.WriteLog("ProcessLogin()", "向" + DataGroup + "用戶:" + UserID + "推送未讀信息和系統消息時出錯." + (ex != null ? ex.Message : ""));
                        }

                        //更新用戶狀態
                        try
                        {
                            DoUpdateUserLog(conn, UserID, "0", ((int)userToken.BindingUser.Mobile).ToString(), DataGroup + "登錄", ((IPEndPoint)userToken.ConnectSocket.RemoteEndPoint).Address.ToString(), DataText, DataTerminalName, null);
                            DoUpdateUserState(conn, UserID, "1"); //上線中
                        }
                        catch (Exception ex)
                        {
                            Passed = false;
                            LogHelper.WriteLog("ProcessLogin()", "更新" + DataGroup + "用戶:" + UserID + "狀態." + (ex != null ? ex.Message : ""));
                        }

                        conn.CloseConnection();
                    }

                    //只推PC端用戶
                    if (Passed && DataGroup.Length == 0)
                    {
                        #region " 向PC客戶端推送平臺數據(在線人數等) "
                        try
                        {
                            List<byte[]> MsgToPC = ParseProtocol.ConvertMsgToByte(string.Format(SysMessage, ActiveUsersCount,
                                                                                                            OnlineUsersCount,
                                                                                                            RegisteredUsersCount,
                                                                                                            TodayMessagesCount,
                                                                                                            TotalMessagesCount),
                                                                                  "9", "", "", "", "", "");
                            //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                            lock (newClient)
                            {
                                foreach (byte[] msg in MsgToPC)
                                {
                                    //2016/05/19 test
                                    userToken.AsyncSendAgent.DoSendBuffer(msg);
                                    //newClient.Send(msg);
                                    //SendData(newClient, msg);
                                }
                            }
                        }
                        catch (SocketException ex)
                        {
                            //這個沒必要斷開
                            //Passed = false;
                            //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "向PC端" + DataTerminal + "推送未讀信息時出錯." + (ex != null ? ex.Message : ""));
                            LogHelper.WriteLog("ProcessLogin()", "向PC端" + UserID + "推送平臺數據(在線人數等)." + (ex != null ? ex.Message : ""));
                        }
                        #endregion

                        #region " 向PC客戶端推送系統公告 "
                        try
                        {
                            if (SysNotices.Count > 0 && UserRegion.Length > 0 && (SysNotices.ContainsKey(UserRegion) || SysNotices.ContainsKey("ALL")))
                            {
                                List<NoticeMsg> nMsgs;
                                // 全服廣播
                                object AllNotices = SysNotices["ALL"];
                                if (AllNotices != null)
                                {
                                    nMsgs = (List<NoticeMsg>)AllNotices;
                                    List<byte[]> MsgNotice;
                                    foreach (NoticeMsg nMsg in nMsgs)
                                    {
                                        MsgNotice = ParseProtocol.ConvertMsgToByte(nMsg.MsgText, "B", "1", nMsg.MsgSeq, "ALL", "", "");
                                        //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                                        lock (newClient)
                                        {
                                            foreach (byte[] msg in MsgNotice)
                                            {
                                                //2016/05/19 test
                                                userToken.AsyncSendAgent.DoSendBuffer(msg);
                                                //newClient.Send(msg);
                                                //SendData(newClient, msg);
                                            }
                                        }
                                    }
                                }
                                // 區域廣播
                                object RegionNotices = SysNotices[UserRegion];
                                if (RegionNotices != null)
                                {
                                    nMsgs = (List<NoticeMsg>)RegionNotices;
                                    List<byte[]> MsgNotice;
                                    foreach (NoticeMsg nMsg in nMsgs)
                                    {
                                        MsgNotice = ParseProtocol.ConvertMsgToByte(nMsg.MsgText, "B", "1", nMsg.MsgSeq, UserRegion, "", "");
                                        //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                                        lock (newClient)
                                        {
                                            foreach (byte[] msg in MsgNotice)
                                            {
                                                //2016/05/19 test
                                                userToken.AsyncSendAgent.DoSendBuffer(msg);
                                                //newClient.Send(msg);
                                                //SendData(newClient, msg);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        catch (SocketException ex)
                        {
                            //這個沒必要斷開
                            //Passed = false;
                            //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "向PC端" + DataTerminal + "推送未讀信息時出錯." + (ex != null ? ex.Message : ""));
                            LogHelper.WriteLog("ProcessLogin()", "向PC端" + UserID + "推送系統公告." + (ex != null ? ex.Message : ""));
                        }
                        #endregion
                    }

                    if (Passed)
                    {
                        //添加到正在執行的列表中
                        if (UserTokenList.ContainsKey(UserID))
                        {
                            ExistsUser = UserTokenList[UserID];
                            if (ExistsUser != null)
                            {
                                try
                                {
                                    LogHelper.WriteLog("DoPcMobileLogin", string.Format("加入在線人員列表時發現已有同名帳號在里面,強制用戶{0} [{1}] 下線.", UserID, ExistsUser.ConnectSocket.RemoteEndPoint));

                                    if (!ExistsUser.Closing)
                                    {
                                        //ExistsUser.Closing = true;
                                        CloseClientSocket(ExistsUser);
                                    }
                                }
                                catch (SocketException ex)
                                {
                                    LogHelper.WriteLog("ProcessLogin()", "嘗試關閉" + DataGroup + "用戶" + UserID + "線程和Socket連接時出錯." + (ex != null ? ex.Message : ""));
                                }
                            }
                            //LogHelper.WriteLog("ProcessLogin()", "#5.加入在線人員列表時發現已有同名帳號在里面. " + UserID + " [" + userToken.ConnectSocket.RemoteEndPoint + "]");
                        }
                        UserTokenList.Add(UserID, userToken);
                        //取消日志
                        //LogHelper.WriteLog("ProcessLogin()", "#6.已加入到在線人員列表. " + UserID + " [" + userToken.ConnectSocket.RemoteEndPoint + "]");
                        //System.Diagnostics.Debug.WriteLine(UserID + " Logged in at " + DateTime.Now.ToString("HH:mm:ss:fff"));
                        Done = true;
                    }
                }
            }
            return Done;
        }
Ejemplo n.º 12
0
 public AudioCallProcessor(AsyncSocketServer asyncSocketServer, SocketUserToken userToken)
     : base(asyncSocketServer, userToken)
 {
     this.ApplyChannelTofSender();
 }
Ejemplo n.º 13
0
        /// <summary>
        /// 處理命令
        /// </summary>
        /// <returns></returns>
        public override bool ProcessCommand(SocketUserToken userToken)
        {
            //開始解包
            DynamicBufferManager receiveBuffer = userToken.ReceiveBuffer;
            string curUserID = userToken.BindingUser.ID;
            string curDevice = (userToken.BindingUser.Role == User.UserRole.PC ? "PC客戶端" : "Mobile客戶端");
            try
            {
                //返回解包后的資料(返回數組 0=type ; 1=終端; 2=群號; 3=時間; 4=消息ID; 5=消息內容 6=終端姓名 7=消息系統編號 8=設置漫遊)
                int msgDataLength = 0;
                object[] ReceiveData = ParseProtocol.UnpackMsgPackage(receiveBuffer.Buffer, out msgDataLength);
                string DataType = ReceiveData[0].ToString();

                //如果數據類別為空就踢出
                if (DataType == "")
                {
                    LogHelper.WriteLog("PcProcessor.ProcessCommand", "讀取" + curDevice + "用戶: @<" + curUserID + " " + userToken.ConnectSocket.RemoteEndPoint + "> 數據時連接異常斷開.");
                    //主動關閉連接
                    //userToken.Closing = true;
                    return false;
                }

                string DataTerminal = ReceiveData[1].ToString();
                string DataGroup = ReceiveData[2].ToString();
                string DataGUID = ReceiveData[4].ToString();
                string DataBody = ((DataType != "I" && DataType != "R") ? ReceiveData[5].ToString() : "N/A"); // 非屏幕截圖時才有值
                byte[] DataImage = ((DataType == "I" || DataType == "R") ? (byte[])ReceiveData[5] : null); // 屏幕截圖時才有值
                string DataTerminalName = ReceiveData[6].ToString();

                //Added by Donnie on 2016/04/27
                //如果是換頭像也不會有值
                if (DataType == "S" && DataTerminalName == "8")
                {
                    DataBody = "N/A";
                    DataImage = (byte[])ReceiveData[5];
                }

                // 分類處理
                switch (DataType)
                {
                    case "1":
                        #region " 用戶離線 "

                        LogHelper.WriteLog("PcProcessor.ProcessCommand", curDevice + "用戶: @<" + curUserID + " " + userToken.ConnectSocket.RemoteEndPoint + "> 離線.");

                        #endregion

                        //主動關閉連接
                        //userToken.Closing = true;
                        return false;
                    case "5":
                        #region " 群(異動)系統訊息 "

                        base.SendGroupSysMessage(DataTerminal, DataGroup, DataGUID, DataBody);

                        #endregion

                        break;
                    case "6":
                        #region " 心跳包 "

                        base.DoAlive(DataTerminal, DataBody, DataType, DataGUID);

                        #endregion

                        break;
                    case "7":
                        #region " 控制臺消息(7-07/7-08) "

                        base.ProcessConsoleCommands(DataBody);

                        #endregion

                        break;

                    case "8":
                        #region " 發送在線用戶ID清單 "

                        base.PushOnlineUserList(DataGroup, DataType, DataGUID);

                        #endregion

                        break;

                    case "B":
                        #region " 系統廣播/公告 - 管理員專用 "
                        try
                        {
                            //DataTerminal:命令(1=播放;0=停止)
                            //DataTerminalName: 項次
                            //DataGroup: 區域(ALL=全服播放;代號=單區播放)
                            //DataBody: 公告內容

                            //using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                            //{
                            //    conn.OpenConnection();
                            //    try
                            //    {
                            //        if (conn.OpenDataTable("select uid from lrbroadcast (nolock) where region_id = '" + DataGroup + "' and bdc_seq = '" + DataTerminalName + "'", CommandType.Text).Rows.Count > 0)
                            //        {
                            //            //有資料
                            //            conn.ExecuteSQL("update a set a.bdc_cmd='" + DataTerminal + "',a.bdc_text=N'" + DataBody + "' from lrbroadcast a where a.region_id = '" + DataGroup + "' and a.bdc_seq = '" + DataTerminalName + "'");
                            //        }
                            //        else
                            //        {
                            //            //沒資料
                            //            if (DataTerminal == "1")
                            //            {
                            //                conn.ExecuteSQL("insert into lrbroadcast (region_id,bdc_seq,bdc_text,bdc_cmd) values('" + DataGroup + "','" + DataTerminalName + "',N'" + DataBody + "','" + DataTerminal + "')");
                            //            }
                            //        }
                            //        conn.CloseConnection();
                            //    }
                            //    catch
                            //    {
                            //        conn.CloseConnection();
                            //    }
                            //}

                            ////1.更新公告內容和區域
                            //lock (base.m_asyncSocketServer.SysNotices.SyncRoot)
                            //{
                            //    if (base.m_asyncSocketServer.SysNotices.ContainsKey(DataGroup))
                            //    {
                            //        //ALL 也會存里面
                            //        List<NoticeMsg> nMsgs = (List<NoticeMsg>)base.m_asyncSocketServer.SysNotices[DataGroup];
                            //        NoticeMsg nMsg = nMsgs.Find(delegate(NoticeMsg _msg) { return _msg.MsgSeq == DataTerminalName; });
                            //        if (nMsg != null)
                            //        {
                            //            if (DataTerminal == "1")
                            //            {
                            //                // 替換現有的公告
                            //                nMsg.MsgText = DataBody;
                            //            }
                            //            else
                            //            {
                            //                // 移除現有的公告
                            //                nMsgs.Remove(nMsg);
                            //                if (nMsgs.Count == 0)
                            //                {
                            //                    // 當前區域沒有公告了,將區域移除
                            //                    base.m_asyncSocketServer.SysNotices.Remove(DataGroup);
                            //                }
                            //            }
                            //        }
                            //        else
                            //        {
                            //            if (DataTerminal == "1")
                            //            {
                            //                // 新公告
                            //                nMsgs.Add(new NoticeMsg() { MsgSeq = DataTerminalName, MsgText = DataBody });
                            //            }
                            //        }
                            //    }
                            //    else
                            //    {
                            //        if (DataTerminal == "1")
                            //        {
                            //            //新公告
                            //            base.m_asyncSocketServer.SysNotices.Add(DataGroup, new List<NoticeMsg>() { new NoticeMsg() { MsgSeq = DataTerminalName, MsgText = DataBody } });
                            //        }
                            //    }
                            //}

                            //2.向區域內的用戶播放
                            base.SendSysNotice(DataTerminal, DataTerminalName, DataGroup, DataBody);
                        }
                        catch (Exception ex)
                        {
                            LogHelper.WriteLog("PcProcessor.ProcessCoommand", "發送服務器廣播時:" + (ex != null ? ex.Message : ""));
                        }

                        #endregion

                        break;

                    case "H":
                        #region " 發送服務器健康報告 "

                        try
                        {
                            //[#1]:120                   [PC端用戶]
                            //[#2]:12                    [移動端用戶]
                            //[#3]:10                    [訂閱號服務端]
                            //[#4]:12/50                 [空閒UserToken]
                            //[#5]:10                    [APP用戶]
                            //[#6]:2                     [文件傳送用戶]
                            //[#7]:0                     [歷史消息標記已讀隊列]
                            //[#8]:89                    [用戶狀態推送隊列]
                            //[#9]:0/10                  [空間狀態推送線程]
                            //[#10]:10                   [設備數據更新隊列]
                            //[#11]:10                   [語音通話客戶]
                            DataBody = "";

                            //[PC端用戶]
                            DataBody += "[#1]:" + m_asyncSocketServer.PcUserTokenList.Count.ToString() + "|";
                            //[移動端用戶]
                            DataBody += "[#2]:" + m_asyncSocketServer.MobileUserTokenList.Count.ToString() + "|";
                            //[訂閱號服務端]
                            DataBody += "[#3]:" + m_asyncSocketServer.SubServiceTokenList.Count.ToString() + "|";
                            //[空閒UserToken]
                            DataBody += "[#4]:" + m_asyncSocketServer.IdleUserTokenPool.Count.ToString() + "/" + m_asyncSocketServer.MaxServerLoading.ToString() + "|";
                            //[APP用戶]
                            DataBody += "[#5]:" + m_asyncSocketServer.AppUserTokenList.Count.ToString() + "|";
                            //[文件傳送用戶]
                            DataBody += "[#6]:" + m_asyncSocketServer.FileUserTokenList.Count.ToString() + "|";
                            //[歷史消息標記已讀隊列]
                            DataBody += "[#7]:" + m_asyncSocketServer.MarkReadHistoryMsgQueue.Count.ToString() + "|";
                            //[用戶狀態推送隊列]
                            DataBody += "[#8]:" + m_asyncSocketServer.StateNotifyQueue.Count.ToString() + "|";
                            //[空間狀態推送線程]
                            DataBody += "[#9]:" + m_asyncSocketServer.StateNofityThreadsQueue.Count.ToString() + "/" + m_asyncSocketServer.MaxStateNotifyThreads.ToString() + "|";
                            //[設備數據更新隊列]
                            DataBody += "[#10]:" + m_asyncSocketServer.VDataQueue.Count.ToString() + "|";
                            //[語音通話客戶]
                            DataBody += "[#11]:" + m_asyncSocketServer.AudioCallTokenList.Count.ToString();

                            List<byte[]> msgs = ParseProtocol.ConvertMsgToByte(DataBody, DataType, DataTerminal, DataTerminalName, "", DataGUID);

                            //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                            lock (userToken.ConnectSocket)
                            {
                                foreach (byte[] msg in msgs)
                                {
                                    //2016/05/19 test
                                    userToken.AsyncSendAgent.DoSendBuffer(msg);
                                    //userToken.ConnectSocket.Send(msg);
                                    //base.SendData(userToken.ConnectSocket, msg);
                                }
                            }
                            //clsClientLog.WriteLog(clsClientLog.LogType.Info, "ThreadFunc(object obj):default", "成功向: " + _receiver + " 發送信息: " + _packetBuff);
                        }
                        catch (Exception ex)
                        {
                            //clsClientLog.WriteLog(clsClientLog.LogType.Error, "ThreadFunc(object obj):default", "發送在線用戶ID清單時:" + ex.Message);
                            LogHelper.WriteLog("PcProcessor.ProcessCoommand", "發送服務器健康報告時時:" + (ex != null ? ex.Message : ""));
                        }

                        #endregion

                        break;
                    case "C":
                        #region " 群命令 "

                        // 抓出群成員
                        using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        {
                            conn.OpenConnection();
                            try
                            {
                                // 記錄到數據庫中
                                //DateTime MsgDT = DateTime.Now;
                                string MsgNO = this.InsertCmd(conn, DataTerminal, DataBody, DataGroup, DataGUID);
                                if (MsgNO.Length > 0)
                                {
                                    // 向管理員發的命令不轉發
                                    if (DataGroup.Length > 0)
                                    {
                                        //系統將命令轉發給群成員(以發送者的帳號) 
                                        base.SendGroupCommand(DataTerminal, DataGroup, DataBody, DataTerminalName, conn, DataGUID, MsgNO);
                                    }
                                    // 轉發完再發回執
                                    // 向發送者發送回執7-03
                                    // 回執給PC端里,必須用DataGUID,因為PC端本地生成的GUID要和這個DataGUID匹配
                                    base.PushFeedback(DataGUID, MsgNO);
                                }
                                conn.CloseConnection();
                            }
                            catch
                            {
                                conn.CloseConnection();
                            }
                        }

                        #endregion

                        break;
                    case "D":
                        #region " 撤回消息 "
                        //0001D發送人帳號(50b)接收對象類別(U=人;G=群)(60b)接收人/接收群(50b)GMT時間(20b)要撤回消息的GUID(32b)訊息流水號(20b)
                        using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        {
                            conn.OpenConnection();
                            try
                            {
                                // 記錄到數據庫中(1=撤回,M=消息lrmsg)
                                string MsgNO = this.InsertSysMsg(conn, DataTerminal, DataBody, "1", "M", (DataTerminalName == "G" ? DataGroup : ""), (DataTerminalName == "U" ? DataGroup : ""), DataGUID);
                                if (MsgNO.Length > 0)
                                {
                                    //系統將訊息轉發給群成員(以發送者的帳號) 
                                    base.SendGroupSysBroadcast("D", "1", "M", DataTerminal, DataGroup, DataBody, DataTerminalName, conn, DataGUID, MsgNO);
                                    // 轉發完再發回執
                                    // 向發送者發送回執7-03
                                    base.PushFeedback(DataGUID, MsgNO);

                                }
                                conn.CloseConnection();
                            }
                            catch
                            {
                                conn.CloseConnection();
                            }
                        }
                        #endregion

                        break;
                    case "G":
                    case "L":

                        #region " 群組訊息(G=Push / L=Pull) "

                        base.SendGroupBroadcast(DataTerminal, DataGroup, DataBody, DataTerminalName, DataGUID, DataType == "G");

                        #endregion

                        break;
                    case "I":
                        #region " 轉發屏幕截圖 "

                        //DataTerminal是接收人帳號(對人)
                        //DataTerminal是發送人帳號(對群)
                        //DataTerminalName是發送人姓名
                        base.SendImage(DataTerminal, DataGroup, DataImage, DataTerminalName, DataGUID);

                        #endregion

                        break;

                    case "U": //人對人信息
                    case "T": //測試工具使用
                        #region " 用戶訊息 "

                        //別搞暈了
                        //DataTerminal是接收人帳號
                        //DataTerminalName是發送人姓名
                        using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        {
                            conn.OpenConnection();
                            try
                            {
                                // 記錄到數據庫中
                                //DateTime MsgDT = DateTime.Now;
                                //T=測試用(超哥神器)
                                string MsgNO = this.InsertMsg(conn, curUserID, DataBody, "", DataTerminal, "1", DataGUID, DataType == "T", true);
                                if (MsgNO.Length > 0)
                                {
                                    //開始發送
                                    base.SendP2PMessage(curUserID, DataTerminalName, DataTerminal, DataBody, conn, DataGUID, MsgNO, DataType);

                                    // 轉發完再發回執
                                    // 向發送者發送回執7-03
                                    base.PushFeedback(DataGUID, MsgNO);
                                }
                                conn.CloseConnection();
                            }
                            catch
                            {
                                conn.CloseConnection();
                            }
                        }

                        #endregion

                        break;
                    case "Q": //抖動
                        #region " 抖動 "
                        //DataTerminal是接收人帳號
                        //DataTerminalName是發送人姓名
                        using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        {
                            conn.OpenConnection();
                            try
                            {
                                // 記錄到數據庫中
                                //DateTime MsgDT = DateTime.Now;
                                string MsgNO = this.InsertMsg(conn, curUserID, DataBody, "", DataTerminal, "1", "", "5", "0", DataGUID, false, true);
                                if (MsgNO.Length > 0)
                                {
                                    //開始發送
                                    base.SendP2PMessage(curUserID, DataTerminalName, DataTerminal, DataBody, conn, DataGUID, MsgNO, DataType);

                                    // 轉發完再發回執
                                    // 向發送者發送回執7-03
                                    base.PushFeedback(DataGUID, MsgNO);
                                }
                                conn.CloseConnection();
                            }
                            catch
                            {
                                conn.CloseConnection();
                            }
                        }
                        #endregion

                        break;

                    case "R":
                        #region " 轉發錄音 "

                        //DataTerminal是接收人帳號(對人)
                        //DataTerminal是發送人帳號(對群)
                        //DataTerminalName是發送人姓名
                        //ReceiveData[7].ToString()是語音時長
                        base.SendVoice(DataTerminal, DataGroup, DataImage, DataTerminalName, DataGUID, ReceiveData[7].ToString());

                        #endregion

                        break;

                    case "S":
                        #region " 聯絡人狀態變更 "
                        //通知在線的聯絡人當前用戶改變了狀態
                        //0=空閒|1=上線|2=離開|3=忙碌|4=不要打擾|5=隱身|6=離線|7=簽名|8=換頭像
                        userToken.BindingUser.SetUserState(DataTerminalName);
                        //特殊處理簽名操作
                        if (DataTerminalName == "7")
                        {
                            //User.ChangeSignature = true;
                            userToken.BindingUser.Signature = DataBody; //signature
                            m_asyncSocketServer.UpdateUserLog(curUserID, "2", "0", userToken.BindingUser.Signature, "", null);
                        }
                        else if (DataTerminalName == "8")
                        {
                            //Added by Donnie on 2016/04/27
                            // 變更頭像的處理
                            m_asyncSocketServer.UpdateUserLog(curUserID, "3", "0", "更新頭像", "", DataImage);
                        }

                        //Added by Donnie on 2016/04/27
                        //ID,狀態,簽名,聯絡人清單,頭像數據
                        if (userToken.BindingUser.Contacts.Count > 0)
                            m_asyncSocketServer.StateNotifyQueue.Enqueue(new List<object>() { curUserID, DataTerminalName, userToken.BindingUser.Signature, userToken.BindingUser.Contacts, DataImage });

                        //Added by Donnie on 2016/04/27
                        //簽名各頭像變更不會影響在線狀態
                        if (DataTerminalName != "7" && DataTerminalName != "8")
                            m_asyncSocketServer.UpdateUserState(curUserID, DataTerminalName); //state
                        #endregion

                        break;
                    case "P":
                        #region " 請求發送文件和同意接受文件 "
                        //發起發送文件請求: 0019P接收人帳號(50b)發起人姓名(60b)S(50b)GMT時間(20b)文檔流的GUID(32b)訊息流水號(20b)
                        //接收人同意請求:   0019P發起人帳號(50b)接收人姓名(60b)R(50b)GMT時間(20b)文檔流的GUID(32b)訊息流水號(20b)
                        //包體: 文件名|大小|文件完整路徑
                        //接收方同意接收的請求等到接收方T通道建立完成再轉發給發送方
                        if (DataGroup != "R" && DataGroup.Length > 0)
                        {
                            switch (DataGroup)
                            {
                                case "Q":
                                    //斷開T通道的對象
                                    //0019P發起人帳號(50b)S(60b)Q(50b)GMT時間(20b)文檔流的GUID(32b)訊息流水號(20b)
                                    //0019P接收人帳號(50b)R(60b)Q(50b)GMT時間(20b)文檔流的GUID(32b)訊息流水號(20b)
                                    if (DataTerminalName == "R")
                                        break; //不再主動斷開接收端(R)T通道連接,由客戶端自主斷開.
                                    string TID = DataGUID + "-" + DataTerminalName;
                                    //LogHelper.WriteLog("ThreadFunc", "準備斷開:" + TID + "的連接...");
                                    SocketUserToken TSocket = m_asyncSocketServer.FileUserTokenList[TID] as SocketUserToken;

                                    if (TSocket != null)
                                    {
                                        //LogHelper.WriteLog("PcProcessor.ProcessCommand", "從S通道斷開:" + TID + ".");
                                        try
                                        {
                                            //主動關閉連接
                                            //TSocket.Closing = true;
                                            m_asyncSocketServer.CloseClientSocket(TSocket);
                                        }
                                        catch
                                        {
                                            LogHelper.WriteLog("CloseClientSocket", "無法從S通道斷開:" + TID + ",可能已從T通道斷開.");
                                        }
                                    }
                                    else
                                    {
                                        LogHelper.WriteLog("PcProcessor.ProcessCommand", "沒有找到:" + TID + ".");
                                    }
                                    break;
                                default:
                                    string MsgNO = base.ProcessTransferFileRequest(curUserID, DataType, DataTerminal, DataGroup, DataGUID, DataBody, DataTerminalName);
                                    // 向發送者發送回執7-03
                                    base.PushFeedback(DataGUID, MsgNO);

                                    break;
                            }
                        }
                        #endregion

                        break;

                    case "K":
                        #region " 踢人7-06 "
                        //0010K踢出目標帳號(50b)空格(60)空格(60)時間(20b)GUID(32b)訊息流水號(20b)
                        //包體:P/M (P=PC端;M=移動端)
                        //向被踢者發送回執7-06

                        SocketUserToken KickTarget = m_asyncSocketServer.PcUserTokenList[DataTerminal] as SocketUserToken;
                        if (DataBody == "M")
                        {
                            KickTarget = m_asyncSocketServer.MobileUserTokenList[DataTerminal] as SocketUserToken;
                            //if (KickTarget == null)
                            //{
                            //    KickTarget = _mobile_transmit_tb[DataTerminal] as UserSocket;
                            //}
                        }
                        if (KickTarget != null)
                        {
                            Socket KickTargetSkt = KickTarget.ConnectSocket;
                            bool ForceKickOut = DataGroup == "F"; //為F表示從服務器端強制斷開
                            try
                            {
                                //回執給PC端里,必須用DataGUID,因為PC端本地生成的GUID要和這個DataGUID匹配
                                List<byte[]> msgs = ParseProtocol.ConvertMsgToByte("06", "7", "", "", "", DataGUID, "");
                                //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息
                                lock (KickTargetSkt)
                                {
                                    if (KickTargetSkt.Connected)
                                    {
                                        foreach (byte[] msg in msgs)
                                        {
                                            //2016/05/19 test
                                            KickTarget.AsyncSendAgent.DoSendBuffer(msg);
                                            //KickTargetSkt.Send(msg);
                                            //base.SendData(KickTargetSkt, msg);
                                        }
                                    }
                                }
                            }
                            catch (SocketException ex)
                            {
                                //客戶端異常,強踢
                                ForceKickOut = true;
                                //clsClientLog.WriteLog(clsClientLog.LogType.Error, "ThreadFunc(object obj):default", "發送消息回執時:" + ex.Message);
                                LogHelper.WriteLog("PcProcessor.ProcessCommand", "發送消息回執時:" + (ex != null ? ex.Message : ""));
                            }

                            #region " 用戶在線就讓其自動登出,否則直接踢出 "
                            //開踢
                            if (ForceKickOut)
                            {
                                //主動關閉連接
                                //KickTarget.Closing = true;
                                m_asyncSocketServer.CloseClientSocket(KickTarget);
                            }
                            #endregion
                        }
                        else
                        {
                            //Kick FileTransferID
                            KickTarget = m_asyncSocketServer.FileUserTokenList[DataTerminal] as SocketUserToken;
                            if (KickTarget != null)
                            {
                                //主動關閉連接
                                //KickTarget.Closing = true;
                                m_asyncSocketServer.CloseClientSocket(KickTarget);
                            }
                        }

                        //通知管理員執行成功7-03
                        base.PushFeedback(DataGUID, "");

                        #endregion

                        break;

                    case "W":
                        #region " 訂閱號消息 "

                        if (DataGroup.Length > 0)
                        {
                            //用戶向訂閱號發命令
                            SendRequestToSubService(DataTerminal, DataGroup, DataBody, DataTerminalName, DataGUID, true);
                        }

                        #endregion

                        break;

                    case "X":
                        #region " 請求和接受語音通話 "
                        //發起請求: 0019X接收人帳號(50b)發起人姓名(60b)S(50b)GMT時間(20b)語音流的GUID(32b)訊息流水號(20b)空格(1b)
                        //接受請求: 0019X發起人帳號(50b)接收人姓名(60b)R(50b)GMT時間(20b)語音流的GUID(32b)訊息流水號(20b)空格(1b)  
                        //包體: 內容暫時沒用
                        //接收方同意接收的請求等到接收方T通道建立完成再轉發給發送方
                        if (DataGroup.Length > 0)
                        {
                            switch (DataGroup)
                            {
                                case "R":
                                    //不做任何動作
                                    break;
                                case "A":
                                    //斷開T通道的對象
                                    //0019X接收人帳號(50b)發起人姓名(60b)A(50b)GMT時間(20b)語音流的GUID(32b)訊息流水號(20b)空格(1b)
                                    //0019X發起人帳號(50b)接收人姓名(60b)A(50b)GMT時間(20b)語音流的GUID(32b)訊息流水號(20b)空格(1b)
                                    base.PushMessage("",
                                                     ParseProtocol.ConvertMsgToByte(DataBody, DataType, curUserID, "AudioUser", DataGroup, DataGUID, "-1"),
                                                     DataTerminal, m_asyncSocketServer.PcUserTokenList, "ProcessCommand-X");
                                    break;
                                default:
                                    base.ProcessAudioCallRequest(curUserID, DataType, DataTerminal, DataGroup, DataGUID, DataBody, DataTerminalName);
                                    break;
                            }
                        }
                        #endregion

                        break;

                    case "Z":
                        #region " 記錄登錄流量和耗時數據 "
                        //DataBody包體格式:
                        //類別A;流量(Byte);耗時(ms);開始(當地)日期(yyyy/MM/dd);開始(當地)時間(HH:mm:ss.fff);結束(當地)日期(yyyy/MM/dd);結束(當地)時間(HH:mm:ss.fff)|類別B;流量(Byte);耗時(ms);開始(當地)日期(yyyy/MM/dd);開始(當地)時間(HH:mm:ss.fff);結束(當地)日期(yyyy/MM/dd);結束(當地)時間(HH:mm:ss.fff)
                        //邏輯:
                        //根據帳號+IP抓到lrlxlog里此用戶最大UID作業log_uid
                        base.SaveLoginStatData(userToken, DataTerminal, DataBody);
                        #endregion

                        break;
                }
                //System.Diagnostics.Debug.WriteLine("清除:" + receiveBuffer.DataCount.ToString() + "個Byte.");
                //把已處理的數據從緩存里清除
                //receiveBuffer.Clear(receiveBuffer.DataCount);
                receiveBuffer.Clear(msgDataLength);
                //扣除已發完的包
                base.m_readyPackage--;

                //發完一個包后,如果DataCount>0說明有粘包數據,嘗試發送出去,否則會影響後面數據的發送效率.
                //如果粘包不是一個完整的數據包就返回去接收數據
                //while (receiveBuffer.DataCount > 0)
                //{
                //    try
                //    {
                //        ProcessCommand(userToken);
                //    }
                //    catch
                //    {
                //        // 繼續收
                //        return true;
                //    }
                //}
                if (base.m_readyPackage > 0)
                    return ProcessCommand(userToken);
                else
                    return true;
                //System.Diagnostics.Debug.WriteLine("剩餘:" + receiveBuffer.DataCount.ToString() + "個Byte.");
                //test
                //System.Diagnostics.Debug.WriteLine(DateTime.Now.ToLongTimeString() + " - " + DataType);
                //return true;
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("PcProcessor.ProcessCommand", string.Format("執行" + curDevice + "用戶:{0}命令時時出錯:{1}.", "@<" + userToken.BindingUser.ID + " " + userToken.ConnectSocket.RemoteEndPoint + "> ", (ex != null ? ex.Message : "")));
                //主動關閉連接
                //userToken.Closing = true;
                return false;
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// 保存登錄流量和耗時數據
        /// </summary>
        /// <param name="userToken"></param>
        /// <param name="DataTerminal"></param>
        /// <param name="DataBody"></param>
        protected void SaveLoginStatData(SocketUserToken userToken, string DataTerminal, string DataBody)
        {
            //DataBody包體格式:
            //類別A;流量(Byte);耗時(ms);開始(當地)日期(yyyy/MM/dd);開始(當地)時間(HH:mm:ss.fff);結束(當地)日期(yyyy/MM/dd);結束(當地)時間(HH:mm:ss.fff)|類別B;流量(Byte);耗時(ms);開始(當地)日期(yyyy/MM/dd);開始(當地)時間(HH:mm:ss.fff);結束(當地)日期(yyyy/MM/dd);結束(當地)時間(HH:mm:ss.fff)
            //邏輯:
            //根據帳號+IP抓到lrlxlog里此用戶最大UID作業log_uid
            string[] StatData = DataBody.Split('|');
            if (StatData.Length > 0)
            {
                DateTime curDate = DateTime.Now;
                string Today = curDate.ToString("yyyy/MM/dd");
                string Yesterday = curDate.AddDays(-1).ToString("yyyy/MM/dd"); //防止登錄時剛好跨天
                using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                {
                    conn.OpenConnection();
                    try
                    {
                        conn._Transaction = conn._Connection.BeginTransaction();

                        DataTable recTmp = conn.OpenDataTable("select MAX(uid) as log_uid from lrlxlog (nolock) " + "\r\n" +
                                                              "where log_date between '" + Yesterday + "' and '" + Today + "' and user_no='" + DataTerminal + "' and log_ip='" + ((IPEndPoint)userToken.ConnectSocket.RemoteEndPoint).Address.ToString() + "'", CommandType.Text);
                        if (recTmp.Rows.Count > 0)
                        {
                            long log_uid = long.Parse(recTmp.Rows[0]["log_uid"].ToString());
                            string[] statValues;
                            foreach (string stat in StatData)
                            {
                                statValues = stat.Split(';');
                                //[0]:類別
                                //[1]:流量(Byte)
                                //[2]:耗時(ms)
                                //[3]:開始(當地)日期(yyyy/MM/dd)
                                //[4]:開始(當地)時間(HH:mm:ss.fff)
                                //[5]:結束(當地)日期(yyyy/MM/dd)
                                //[6]:結束(當地)時間(HH:mm:ss.fff)
                                if (statValues.Length == 7)
                                {
                                    conn.ExecuteSQL("insert into lrlxstat (log_uid,stat_type,data_size,duration_time,stat_sdate,stat_stime,stat_edate,stat_etime,ie_ymd,ie_time,ie_user)" + "\r\n" +
                                                    "values(" + log_uid + ",'" + statValues[0] + "'," + statValues[1] + "," + statValues[2] + ",'" + statValues[3] + "','" + statValues[4] + "','" + statValues[5] + "','" + statValues[6] + "','" + curDate.ToString("yyyy/MM/dd") + "','" + curDate.ToString("HH:mm:ss") + "','" + DataTerminal + "')");
                                }
                            }
                        }
                        conn._Transaction.Commit();
                        conn.CloseConnection();
                    }
                    catch
                    {
                        conn._Transaction.Rollback();
                        conn.CloseConnection();
                    }
                }
            }
        }
Ejemplo n.º 15
0
 public FileProcessor(AsyncSocketServer asyncSocketServer, SocketUserToken userToken)
     : base(asyncSocketServer, userToken)
 {
     TransferDone = false;
     this.ApplyChannelTofSender();
 }
Ejemplo n.º 16
0
        ///// <summary>
        ///// 收集監視器數據之命令統計開始
        ///// </summary>
        //private void CommandStatStart()
        //{
        //    //命令當前并發數
        //    ServerStatistics.Concurrent_Commands++;
        //    //命令最高并發數
        //    if (ServerStatistics.MaxConcurrent_Commands < ServerStatistics.Concurrent_Commands)
        //        ServerStatistics.MaxConcurrent_Commands = ServerStatistics.Concurrent_Commands;
        //}

        ///// <summary>
        ///// 收集監視器數據之命令統計結束
        ///// </summary>
        //private void CommandStatEnd(long ElapsedMilliseconds)
        //{
        //    //命令當前并發數
        //    ServerStatistics.Concurrent_Commands--;
        //    //命令當前執行時長(ms)
        //    ServerStatistics.DurationTime_Command = (int)ElapsedMilliseconds;
        //    //命令最大執行時長(ms)
        //    if (ServerStatistics.MaxDurationTime_Command < ServerStatistics.DurationTime_Command)
        //        ServerStatistics.MaxDurationTime_Command = ServerStatistics.DurationTime_Command;
        //}

        /// <summary>
        /// 掃描所有可以發送的完整包
        /// </summary>
        /// <param name="userToken"></param>
        /// <param name="receiveBuffer"></param>
        /// <returns></returns>
        private bool PreparePackages(SocketUserToken userToken, DynamicBufferManager receiveBuffer)
        {
            try
            {
                //error = false;
                //Test
                //System.Diagnostics.Debug.WriteLine("調用:PreparePackages...");
                //System.Text.Encoding.UTF8.GetString(LxTcpServer.Protocol.ParseProtocol.GetByteBuffer(receiveBuffer.Buffer, 0, receiveBuffer.DataCount)).TrimEnd('\0')
                bool CommandResult = false;
                Stopwatch sw = new Stopwatch();
                //判斷緩存中剩餘的數據是否足夠計算完整包
                if (receiveBuffer.DataCount - m_packageOffset < MSGINFOHEAD.BodyLength)
                {
                    if (m_readyPackage > 0)
                    {
                        //已經收集到所有可發送的完整包
                        //m_doProcessCommand = true;
                        //return true;
                        userToken.FirstPacket = true;
                        m_packageOffset = 0;

                        //收集監視器數據之命令統計開始
                        ServerStatistics.CommandStatStart();
                        //開始計時
                        sw.Start();
                        //開始發送
                        CommandResult = ProcessCommand(userToken);
                        //結束計時
                        sw.Stop();
                        //收集監視器數據之命令統計結束
                        ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds);
                        //重置計時器
                        sw.Reset();

                        return CommandResult;
                    }
                    else
                    {
                        //繼續收
                        return true;
                    }
                }

                int DataLen = 0;
                // #Mark 5#  <-不要刪除這個標記!!
                //1.包體長度(16進制轉10進制)
                byte[] DataLenBuffer = ParseProtocol.GetByteBuffer(receiveBuffer.Buffer, m_packageOffset, MSGINFOHEAD.BodyLength);
                try
                {
                    DataLen = ParseProtocol.Convert16To10(Encoding.UTF8.GetString(DataLenBuffer));
                    if (DataLen == 0)
                    {
                        //如果類別不是S(簽名為空),就說明數據錯誤.
                        if (Encoding.UTF8.GetString(receiveBuffer.Buffer, m_packageOffset + MSGINFOHEAD.BodyLength, 1) != "S")
                        {
                            //視為異常
                            DataLen = -1;
                        }
                    }
                }
                catch
                {
                    //異常
                    DataLen = -1;
                }
                //如果是用戶修改簽名為空白,此處就是0.
                //if (DataLen == 0)
                if (DataLen < 0)
                {
                    //if (userToken.BindingUser != null && userToken.ConnectSocket != null && userToken.ConnectSocket.Connected)
                    //{
                    //    #region " 沒找到出錯原因,暫時特殊處理一下 "

                    //    try
                    //    {
                    //        if (m_packageOffset == 1026 && !userToken.FirstPacket && receiveBuffer.DataCount == 1056)
                    //        {
                    //            //先針對1026 - 1056的錯誤特別處理一下
                    //            //錯誤描述:客戶端:D026533信息異常,包頭:    的長度小於0. PackageOffset:1026.FirstPackage:False.
                    //            //         完整信息(Bytes:1056):00016D026533
                    //            //修正 PackageOffset 和 FirstPackage
                    //            m_packageOffset = 0;
                    //            userToken.FirstPacket = true;
                    //            DataLen = 1;
                    //            string msg = Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount);
                    //            LogHelper.WriteLog("BaseProcessor.PreparePackages", "發生1026-1056錯誤,數據已修正." + "\r\n完整信息(緩存Bytes:" + receiveBuffer.DataCount.ToString() + ",取出數據實際長度:" + msg.Length.ToString() + "):" + msg);
                    //        }
                    //        else if (m_packageOffset == 5121 && !userToken.FirstPacket && receiveBuffer.DataCount == 5131)
                    //        {
                    //            //先針對5121 - 5131的錯誤特別處理一下 ==>> 這個問題已經解了:因為未對簽名為空的情況進行處理,數據總長應該加上尾包長度,再去移除) <<==
                    //            //錯誤描述:客戶端:D037198信息異常,包頭:    的長度小於0. PackageOffset:5121.FirstPackage:False.
                    //            //         完整信息(Bytes:5131):100016D037198
                    //            //將第一位無效數據移除
                    //            receiveBuffer.Clear(1);
                    //            //修正 PackageOffset 和 FirstPackage
                    //            m_packageOffset = 0;
                    //            userToken.FirstPacket = true;
                    //            DataLen = 1;
                    //            string msg = Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount);
                    //            LogHelper.WriteLog("BaseProcessor.PreparePackages", "發生5121-5131錯誤,數據已修正." + "\r\n完整信息(緩存Bytes:" + receiveBuffer.DataCount.ToString() + ",取出數據實際長度:" + msg.Length.ToString() + "):" + msg);
                    //        }
                    //    }
                    //    catch(Exception ex)
                    //    {
                    //        LogHelper.WriteLog("BaseProcessor.PreparePackages", "嘗試修正數據時出錯:" + ex.Message);
                    //        return false;
                    //    }

                    //    #endregion
                    //}
                    //else
                    //{
                    if (userToken.BindingUser != null)
                        LogHelper.WriteLog("BaseProcessor.PreparePackages", "客戶端:" + userToken.BindingUser.ID + "信息異常,包頭:" + Encoding.UTF8.GetString(DataLenBuffer) + "的長度小於0. PackageOffset:" + m_packageOffset.ToString() + ".FirstPackage:" + userToken.FirstPacket.ToString() + ".\r\n完整信息(Bytes:" + receiveBuffer.DataCount.ToString() + "):" + Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount)); //.TrimEnd('\0')
                    else
                        LogHelper.WriteLog("BaseProcessor.PreparePackages", "UserToken.BindingUser為空.信息異常,包頭:" + Encoding.UTF8.GetString(DataLenBuffer) + "的長度小於0.");//.TrimEnd('\0')
                    return false;
                    //}
                }

                //$Mark 1$  <-不要刪除這個標記!!
                //包頭+包體+包尾長度比當前已經收到的長度大.(需要加上包頭和包尾的長度)
                if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength + m_packageOffset > receiveBuffer.DataCount)
                {
                    if (m_readyPackage > 0)
                    {
                        //已經收集到所有可發送的完整包
                        //m_doProcessCommand = true;
                        //return true;
                        userToken.FirstPacket = true;
                        m_packageOffset = 0;

                        //收集監視器數據之命令統計開始
                        ServerStatistics.CommandStatStart();
                        //開始計時
                        sw.Start();
                        //開始發送
                        CommandResult = ProcessCommand(userToken);
                        //結束計時
                        sw.Stop();
                        //收集監視器數據之命令統計結束
                        ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds);
                        //重置計時器
                        sw.Reset();

                        return CommandResult;
                    }
                    else
                    {
                        //如果有續包就讀取完成再解包
                        //====================================================================================
                        //====== 以下是分析為什麼偶爾出現心跳包解包錯誤,而m_packageOffset永遠是6的問題 =======
                        //心跳標準長1024+1+1,如果此時receiveBuffer.DataCount沒收足夠(假設只收了1024).就會運行到這里.
                        //此時如果把FirstPacket標記為false并再次接收,就會進入 #Mark 1# 處.
                        //按下來m_packageOffset會被賦值為4+1+1,那麼tailData必然不是1,就進入 #Mark 2# 
                        //因為之前一個完整包都沒收到,所以m_readyPackage是0,必然進入 #Mark 3# 
                        //接下來按FirstPacket為false計算數據包標準長并與receiveBuffer.DataCount比效后,必然進入 #Mark 4#
                        //至此,m_packageOffset變成了6,執行 #Mark 5# 時就報錯了.
                        //====================================================================================
                        //userToken.FirstPacket = false;
                        //解決方案:
                        if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength > receiveBuffer.DataCount)
                        {
                            //目前收到的包還不夠一個標準包長,那就視為是首包
                            userToken.FirstPacket = true;
                        }
                        else
                        {
                            //目前收到的包超過了一個標準包長,那就視為是續包
                            userToken.FirstPacket = false;
                        }
                        return true;
                    }
                }
                else
                {
                    // #Mark 1#  <-不要刪除這個標記!!
                    //收取完整,開始分析是否是完全數據(尾包為1)
                    //記錄下一個包的起始位置
                    m_packageOffset += ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength;
                    string tailData = Encoding.UTF8.GetString(userToken.ReceiveBuffer.Buffer, m_packageOffset - MSGINFOEND.EofLength, MSGINFOEND.EofLength).TrimEnd('\0');
                    if (tailData == "1")
                    {
                        //當前包收取結束
                        //Test
                        //System.Diagnostics.Debug.WriteLine("發出:" + m_packageLength.ToString());
                        //System.Diagnostics.Debug.WriteLine("Buffer Total:" + receiveBuffer.DataCount.ToString());

                        //收好了(至少有一個完整的包可以發送),開始解包并處理命令
                        userToken.FirstPacket = true;
                        //累計待發送的包個數(由ProcessCommand清除)
                        m_readyPackage++;
                        //後面達不到最小包長度就放棄掃描
                        DataLen = 1;
                        if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength + m_packageOffset > receiveBuffer.DataCount)
                        {
                            //m_doProcessCommand = true;
                            m_packageOffset = 0;

                            //收集監視器數據之命令統計開始
                            ServerStatistics.CommandStatStart();
                            //開始計時
                            sw.Start();
                            //開始發送
                            CommandResult = ProcessCommand(userToken);
                            //結束計時
                            sw.Stop();
                            //收集監視器數據之命令統計結束
                            ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds);
                            //重置計時器
                            sw.Reset();

                            return CommandResult;
                        }
                        else
                        {
                            //Test
                            //LogHelper.WriteLog("BaseProcessor.PreparePackages", "尾包值為1(位置:" + (m_packageOffset - 1).ToString() + "),FirstPacket:" + userToken.FirstPacket.ToString() + ",下次將從" + m_packageOffset.ToString() + "開始檢查首包長度.\r\n完整信息(Bytes:" + receiveBuffer.DataCount.ToString() + "):" + Encoding.UTF8.GetString(receiveBuffer.Buffer, 0, receiveBuffer.DataCount).TrimEnd('\0'));

                            //再掃描一次(不用再去接收)
                            return PreparePackages(userToken, receiveBuffer);
                        }
                    }
                    else
                    {
                        // #Mark 2#  <-不要刪除這個標記!!
                        //接下來的一個包一定是續包
                        userToken.FirstPacket = false;

                        if (m_readyPackage > 0)
                        {
                            //雖然是續包,已經收集到所有可發送的完整包,剩下來的數據0位置就是首包
                            userToken.FirstPacket = true;//<-- 2016/04/20 19:51 被1029問題坑得發瘋的時候加的,之前這句沒加...
                            //=============================== 以下是1029錯誤的故事 ===============================
                            //如果這里不賦為true,那麼m_packageOffset被置0后執行ProcessCommand,完成后執行到 #Mark 1#,
                            //然后m_packageOffset會被設置為1029(4+1024+1), 隨後來到 #Mark 2#, 最後 #Mark 3#. 無論此處走哪邊,
                            //都會重新進入PreparePackages,並且此時m_packageOffset為1029,userToken.FirstPacket為false.
                            //但Buffer剩下的卻是一個以首包開始完整數據,結果崩壞!
                            //====================================================================================
                            m_packageOffset = 0;

                            //收集監視器數據之命令統計開始
                            ServerStatistics.CommandStatStart();
                            //開始計時
                            sw.Start();
                            //開始發送
                            CommandResult = ProcessCommand(userToken);
                            //結束計時
                            sw.Stop();
                            //收集監視器數據之命令統計結束
                            ServerStatistics.CommandStatEnd(sw.ElapsedMilliseconds);
                            //重置計時器
                            sw.Reset();

                            return CommandResult;
                        }
                        else
                        {
                            // #Mark 3#  <-不要刪除這個標記!!
                            //如果剩餘已接收數據還可以檢查一次就直接比較
                            DataLen = 1;
                            if (ParseProtocol.GetHeadPacketLength(userToken.FirstPacket) + DataLen + MSGINFOEND.EofLength + m_packageOffset <= receiveBuffer.DataCount)
                            {
                                // #Mark 4#  <-不要刪除這個標記!!
                                return PreparePackages(userToken, receiveBuffer);
                            }
                            else
                            {
                                //繼續接收數據(有效位置就從m_packageOffset開始)
                                return true;
                            }
                        }
                    }
                }
            }
            catch
            {
                //error = true;
                //主動關閉連接
                //userToken.Closing = true;
                return false;
            }
        }
Ejemplo n.º 17
0
 /// <summary>
 /// 處理命令
 /// </summary>
 /// <returns>True=繼續投遞;False=異常</returns>
 public virtual bool ProcessCommand(SocketUserToken userToken)
 {
     //主動關閉連接
     //userToken.Closing = true;
     return false;
 }
Ejemplo n.º 18
0
        public override bool ProcessCommand(SocketUserToken userToken)
        {
            DynamicBufferManager receiveBuffer = userToken.ReceiveBuffer;
            string curUserID = userToken.BindingUser.ID;
            //傳送文件包數據
            SocketUserToken Receiver = m_asyncSocketServer.FileUserTokenList[DataTerminal] as SocketUserToken;

            if (PackageCount == 0 && LastPackageLength == 0)
            {
                receiveBuffer.Clear();
                //全部發送完成,等待S通知發出斷開命令
                TransferDone = true;
                return TransferDone;
            }

            //包體長度比當前已經收到的長度大.20KB或尾包大小
            int DataLength = PackageCount > 0 ? PackageLength : LastPackageLength;
            if (DataLength > receiveBuffer.DataCount)
            {
                //不足一個包的長度,繼續接收.
                return true;
            }
            else
            {
                //足夠一個包或多個包長度,進行分析
                //轉發
                //T通道不用鎖住線程
                try
                {
                    //只發一個包的大小
                    base.SendData(Receiver.ConnectSocket, receiveBuffer.Buffer, DataLength);
                    TotalSize -= DataLength;
                    //把已處理的數據從緩存里清除
                    receiveBuffer.Clear(DataLength);
                    if (PackageCount > 0)
                        PackageCount--;  //收好一個包了,包數減1
                    else
                        LastPackageLength = 0; //尾包扣除

                    //檢查是否發完
                    if (PackageCount <= 0 && LastPackageLength == 0 || TotalSize == 0)
                    {
                        receiveBuffer.Clear();
                        //後面沒有數據了,應該斷開兩邊的連接.
                        string GUID = curUserID.Substring(0, curUserID.Length - 2);
                        bool sent = false;
                        //向發送人和接收人發信息(S通道)
                        #region " Receiver "
                        //好像接收者接收完成后會自己斷掉T通道.明天問問小陽.
                        //如果是這樣那就不需要再用S通道通知接收者斷開T通道了 -> 已確認不需要通知接收者斷開T
                        //S通道
                        //sent = base.PushMessage("", ParseProtocol.ConvertMsgToByte("Complete", "P", userToken.BindingUser.ReceiverID, "", "C", GUID, ""),
                        //                            userToken.BindingUser.ReceiverID,
                        //                            m_asyncSocketServer.PcUserTokenList,
                        //                            "FileProcessor.ProcessReceive").Length > 0;
                        //if (!sent)
                        //{
                        //    //斷開T通道的Receiver
                        //    string RID = curUserID.Substring(0, curUserID.Length - 1) + "R";
                        //    SocketUserToken RUser = m_asyncSocketServer.FileUserTokenList[RID] as SocketUserToken;
                        //    m_asyncSocketServer.CloseClientSocket(RUser);
                        //    LogHelper.WriteLog("FileThreadFunc", "文件傳送完成,強行斷開接收端" + userToken.BindingUser.ReceiverID + "的連接.");
                        //}
                        //else
                        //{
                        //    LogHelper.WriteLog("FileThreadFunc", "文件傳送完成,通知接收端" + userToken.BindingUser.ReceiverID + "斷開連接.");
                        //}

                        #endregion

                        #region " Sender "
                        //S通道
                        sent = base.PushMessage("", ParseProtocol.ConvertMsgToByte("Complete", "P", userToken.BindingUser.SenderID, "", "C", GUID, ""),
                                                    userToken.BindingUser.SenderID,
                                                    m_asyncSocketServer.PcUserTokenList,
                                                    "FileProcessor.ProcessReceive").Length > 0;
                        if (!sent)
                        {
                            //斷開T通道的Sender
                            LogHelper.WriteLog("FileProcessor.ProcessCommand", "文件傳送完成,強行斷開發送者" + userToken.BindingUser.SenderID + "的連接.");
                            //主動關閉連接
                            //userToken.Closing = true;
                            return false;
                        }
                        else
                        {
                            LogHelper.WriteLog("FileProcessor.ProcessCommand", "文件傳送完成,通知發送者" + userToken.BindingUser.SenderID + "斷開連接.");
                        }

                        #endregion

                        return true;
                    }
                    else
                    {                    
                        //如果已收到的數據里還有完整包,在這里就直接發出.不需要再去接收
                        //否則返回去繼續收數據
                        return ProcessCommand(userToken);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.WriteLog("FileProcessor.ProcessCommand", "向接收端:" + DataTerminal + "發送文件整包數據時出錯." + (ex != null ? ex.Message : ""));
                    //異常
                    return CloseBothSide(curUserID);
                }
            }
        }
Ejemplo n.º 19
0
        /// <summary>
        /// 處理命令
        /// </summary>
        /// <returns></returns>
        public override bool ProcessCommand(SocketUserToken userToken)
        {
            //開始解包
            DynamicBufferManager receiveBuffer = userToken.ReceiveBuffer;
            string curUserID = userToken.BindingUser.ID;
            try
            {
                //返回解包后的資料(返回數組 0=type ; 1=終端; 2=群號; 3=時間; 4=消息ID; 5=消息內容 6=終端姓名 7=消息系統編號 8=設置漫遊)
                int msgDataLength = 0;
                object[] ReceiveData = ParseProtocol.UnpackMsgPackage(receiveBuffer.Buffer, out msgDataLength);
                string DataType = ReceiveData[0].ToString();

                //如果數據類別為空就踢出
                if (DataType == "")
                {
                    LogHelper.WriteLog("SubSrvProcessor.ProcessCommand", "讀取用戶: @<" + curUserID + " " + userToken.ConnectSocket.RemoteEndPoint + "> 數據時連接異常斷開.");

                    //主動關閉連接
                    //userToken.Closing = true;
                    return false;
                }

                string DataTerminal = ReceiveData[1].ToString();
                string DataGroup = ReceiveData[2].ToString();
                string DataGUID = ReceiveData[4].ToString();
                string DataBody = (DataType != "I" ? ReceiveData[5].ToString() : "N/A"); // 非屏幕截圖時才有值
                byte[] DataImage = (DataType == "I" ? (byte[])ReceiveData[5] : null); // 屏幕截圖時才有值
                string DataTerminalName = ReceiveData[6].ToString();

                //Test
                //System.Diagnostics.Debug.WriteLine("轉發:\r\n" + DataBody);

                // 分類處理
                switch (DataType)
                {
                    case "1":
                        #region " 用戶離線 "

                        //LogHelper.WriteLog("AppProcessor.ProcessCommand", "用戶:" + curUserID + "離線.");
                        LogHelper.WriteLog("SubSrvProcessor.ProcessCommand", "用戶: @<" + curUserID + " " + userToken.ConnectSocket.RemoteEndPoint + "> 離線.");

                        #endregion

                        //主動關閉連接
                        //userToken.Closing = true;
                        return false;

                    case "6":
                        #region " 心跳包 "

                        base.DoAlive(DataTerminal, DataBody, DataType, DataGUID);

                        #endregion

                        break;

                    case "W":
                        #region " 轉發訂閱號返回的結果給用戶 "

                        if (DataGroup.Length > 0)
                        {
                            //訂閱號返回數據
                            //DataTerminal:接收人
                            SendSubServiceFeedbackToUser(DataTerminal, DataGroup, DataBody, DataGUID);
                        }

                        #endregion

                        break;
                }

                //把已處理的數據從緩存里清除
                //receiveBuffer.Clear(receiveBuffer.DataCount);
                receiveBuffer.Clear(msgDataLength);
                //扣除已發完的包
                base.m_readyPackage--;
                
                //發完一個包后,如果DataCount>0說明有粘包數據,嘗試發送出去,否則會影響後面數據的發送效率.
                //如果粘包不是一個完整的數據包就返回去接收數據
                if (base.m_readyPackage > 0)
                    return ProcessCommand(userToken);
                else
                    return true;
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("SubSrvProcessor.ProcessCommand", string.Format("執行用戶:{0}命令時時出錯:{1}.", curUserID, (ex != null ? ex.Message : "")));
                //主動關閉連接
                userToken.Closing = true;
                return false;
            }
        }
Ejemplo n.º 20
0
 public SubSrvProcessor(AsyncSocketServer asyncSocketServer, SocketUserToken userToken)
     : base(asyncSocketServer, userToken)
 {
 }
Ejemplo n.º 21
0
 public void Remove(SocketUserToken userToken)
 {
     lock (m_table.SyncRoot)
     {
         string UserID = userToken.BindingUser.ID;
         //訂閱號ID特殊處理
         if (userToken.BindingUser.Role == User.UserRole.SubService)
             UserID = "#" + userToken.BindingUser.ID + "#";
         m_table.Remove(UserID);
         //收集監視器數據之在線數統計-減少
         LxTcpServer.SrvMonitor.ServerStatistics.OnlineStatRemove(userToken.BindingUser.Role);
     }
 }
Ejemplo n.º 22
0
        public AsyncSocketServer()
        {
            SocketUserToken userToken;

            //服務器允許的最大連接數
            m_maxServerLoading = int.Parse((string)ConfigurationManager.AppSettings["MaxServerLoading"]);
            ServerStatistics.MaxServerLoading = m_maxServerLoading;

            //推送廣播間隔時間
            PushDataDelay = int.Parse((string)ConfigurationManager.AppSettings["PushDataDelay"]);
            //處理用戶在線狀態推送的線程數量
            MaxStateNotifyThreads = int.Parse((string)ConfigurationManager.AppSettings["MaxStateNotifyThreads"]);
            ServerStatistics.MaxUserState_PushQueue = MaxStateNotifyThreads;
            
            //抓DB信息
            string DBAlias = (string)ConfigurationManager.AppSettings["DB"];

            //縮略圖寬度
            ServerConst.Thumbnail_Width = int.Parse(ConfigurationManager.AppSettings["Thumbnail_Width"]);
            //縮略圖寬度
            ServerConst.Thumbnail_Height = int.Parse(ConfigurationManager.AppSettings["Thumbnail_Height"]);
            //縮略圖寬度
            ServerConst.Thumbnail_Quality = int.Parse(ConfigurationManager.AppSettings["Thumbnail_Quality"]);
            //同時開放多少個語音通話客戶端登錄
            ServerConst.AudioCall_Channels = int.Parse(ConfigurationManager.AppSettings["AudioCall_Channels"]);
            ServerStatistics.AudioCall_Channels = ServerConst.AudioCall_Channels;

            m_receiveBufferSize = ServerConst.ReceiveBufferSize;

            m_idleUserTokenPool = new SocketUserTokenPool(m_maxServerLoading);
            m_pcUserTokenList = new SocketUserTokenList();
            m_mobileUserTokenList = new SocketUserTokenList();
            m_fileUserTokenList = new SocketUserTokenList();
            m_appUserTokenList = new SocketUserTokenList();
            m_subServiceTokenList = new SocketUserTokenList();
            m_audioCallTokenList = new SocketUserTokenList();
            m_maxNumberAcceptedClients = new Semaphore(m_maxServerLoading, m_maxServerLoading);

            //按照連接數建立UserToken
            for (int i = 0; i < m_maxServerLoading; i++)
            {
                userToken = new SocketUserToken(m_receiveBufferSize);
                userToken.ReceiveEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
                userToken.SendEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
                m_idleUserTokenPool.Push(userToken);
            }

            this.CheckOS();
            this.DBInfo = RegHelper.GetDBInfo(DBAlias, RegURL);
        }
Ejemplo n.º 23
0
        public override bool ProcessCommand(SocketUserToken userToken)
        {
            DynamicBufferManager receiveBuffer = userToken.ReceiveBuffer;
            string curUserID = userToken.BindingUser.ID;
            int totalData = 0;
            bool Sent = false;
            //傳送文件包數據
            SocketUserToken Receiver = m_asyncSocketServer.AudioCallTokenList[DataTerminal] as SocketUserToken;

            //轉發
            //T通道不用鎖住線程
            try
            {
                if (Receiver != null && Receiver.ConnectSocket != null && Receiver.ConnectSocket.Connected)
                {
                    totalData = base.SendData(Receiver.ConnectSocket, receiveBuffer.Buffer, receiveBuffer.DataCount);
                    //System.Diagnostics.Debug.WriteLine(totalData);
                    if (totalData == receiveBuffer.DataCount)
                        Sent = true;
                    else
                        Sent = false;
                }
                else
                {
                    Sent = false;
                }
                //把已處理的數據從緩存里清除
                receiveBuffer.Clear(receiveBuffer.DataCount);
                if (Sent)
                {
                    return Sent;
                }
                else
                {
                    LogHelper.WriteLog("AudioCallProcessor.ProcessCommand", "找不到接收端:" + DataTerminal + "或接收者已斷開網絡");
                    //異常
                    //return CloseBothSideOfAudioCall(curUserID);
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("AudioCallProcessor.ProcessCommand", "向接收端:" + DataTerminal + "發送語音整包數據時出錯." + (ex != null ? ex.Message : ""));
                //異常
                //return CloseBothSideOfAudioCall(curUserID);
                return false;
            }
        }
Ejemplo n.º 24
0
        /// <summary>
        /// 處理命令
        /// </summary>
        /// <returns></returns>
        public override bool ProcessCommand(SocketUserToken userToken)
        {
            //開始解包
            DynamicBufferManager receiveBuffer = userToken.ReceiveBuffer;
            string curUserID = userToken.BindingUser.ID;
            try
            {
                //返回解包后的資料(返回數組 0=type ; 1=終端; 2=群號; 3=時間; 4=消息ID; 5=消息內容 6=終端姓名 7=消息系統編號 8=設置漫遊)
                int msgDataLength = 0;
                object[] ReceiveData = ParseProtocol.UnpackMsgPackage(receiveBuffer.Buffer, out msgDataLength);
                string DataType = ReceiveData[0].ToString();

                //如果數據類別為空就踢出
                if (DataType == "")
                {
                    //LogHelper.WriteLog("AppProcessor.ProcessCommand", "讀取用戶:" + curUserID + "數據時連接異常斷開.");
                    LogHelper.WriteLog("AppProcessor.ProcessCommand", "讀取用戶: @<" + curUserID + " " + userToken.ConnectSocket.RemoteEndPoint + "> 數據時連接異常斷開.");

                    //主動關閉連接
                    //userToken.Closing = true;
                    return false;
                }

                string DataTerminal = ReceiveData[1].ToString();
                string DataGroup = ReceiveData[2].ToString();
                string DataGUID = ReceiveData[4].ToString();
                string DataBody = (DataType != "I" ? ReceiveData[5].ToString() : "N/A"); // 非屏幕截圖時才有值
                byte[] DataImage = (DataType == "I" ? (byte[])ReceiveData[5] : null); // 屏幕截圖時才有值
                string DataTerminalName = ReceiveData[6].ToString();

                //Test
                //System.Diagnostics.Debug.WriteLine("轉發:\r\n" + DataBody);

                // 分類處理
                switch (DataType)
                {
                    case "1":
                        #region " 用戶離線 "

                        //LogHelper.WriteLog("AppProcessor.ProcessCommand", "用戶:" + curUserID + "離線.");
                        LogHelper.WriteLog("AppProcessor.ProcessCommand", "用戶: @<" + curUserID + " " + userToken.ConnectSocket.RemoteEndPoint + "> 離線.");

                        #endregion

                        //主動關閉連接
                        //userToken.Closing = true;
                        return false;
                    case "5":
                        #region " 群(異動)系統訊息 "

                        base.SendGroupSysMessage(DataTerminal, DataGroup, DataGUID, DataBody);

                        #endregion

                        break;
                    case "6":
                        //Test
                        //System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-> 收到心跳:" + DataBody);

                        #region " 心跳包 "

                        base.DoAlive(DataTerminal, DataBody, DataType, DataGUID);

                        #endregion

                        break;
                    case "C":
                        #region " 群命令 "

                        // 抓出群成員
                        using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        {
                            conn.OpenConnection();
                            try
                            {
                                // 記錄到數據庫中
                                //DateTime MsgDT = DateTime.Now;
                                string MsgNO = this.InsertCmd(conn, DataTerminal, DataBody, DataGroup, DataGUID);
                                if (MsgNO.Length > 0)
                                {
                                    // 向管理員發的命令不轉發
                                    if (DataGroup.Length > 0)
                                    {
                                        //系統將命令轉發給群成員(以發送者的帳號) 
                                        base.SendGroupCommand(DataTerminal, DataGroup, DataBody, DataTerminalName, conn, DataGUID, MsgNO);
                                    }
                                    // 轉發完再發回執
                                    // 向發送者發送回執7-03
                                    // 回執給PC端里,必須用DataGUID,因為PC端本地生成的GUID要和這個DataGUID匹配
                                    base.PushFeedback(DataGUID, MsgNO);
                                }
                                conn.CloseConnection();
                            }
                            catch
                            {
                                conn.CloseConnection();
                            }
                        }

                        #endregion

                        break;
                    case "G":
                    case "L":

                        #region " 群組訊息(G=Push / L=Pull) "

                        base.SendGroupBroadcast(DataTerminal, DataGroup, DataBody, DataTerminalName, DataGUID, DataType == "G");

                        //// 抓出群成員
                        //using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        //{
                        //    conn.OpenConnection();
                        //    try
                        //    {
                        //        // 記錄到數據庫中
                        //        // DataType == "L"時, DataTerminalName為Pull消息子分類
                        //        string MsgNO = this.InsertMsg(conn, DataTerminal, DataBody, DataGroup, "", "1", (DataType == "G" ? "" : DataTerminalName), DataGUID, false, DataType == "G");
                        //        if (MsgNO.Length > 0)
                        //        {
                        //            // 系統將訊息轉發給群成員(以發送者的帳號) 
                        //            base.SendGroupBroadcast(DataTerminal, DataGroup, DataBody, DataTerminalName, conn, DataGUID, MsgNO, DataType == "G");

                        //            // 轉發完再發回執
                        //            // 向發送者發送回執7-03
                        //            base.PushFeedback(DataGUID, MsgNO);
                        //        }
                        //        conn.CloseConnection();
                        //    }
                        //    catch
                        //    {
                        //        conn.CloseConnection();
                        //    }
                        //}

                        #endregion

                        break;
                    case "A":
                        #region " 外接APP向人發信息 "

                        //DataTerminal是發送人帳號
                        //DataTerminalName是發送人姓名
                        //DataGroup是接收人帳號
                        this.SendAppMessage(curUserID, DataTerminal, DataTerminalName, DataGroup, DataBody, DataGUID);

                        #endregion

                        break;
                    case "D":
                        #region " 撤回消息 "
                        //0001D發送人帳號(50b)接收對象類別(U=人;G=群)(60b)接收人/接收群(50b)GMT時間(20b)要撤回消息的GUID(32b)訊息流水號(20b)
                        using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        {
                            conn.OpenConnection();
                            try
                            {
                                // 記錄到數據庫中(1=撤回,M=消息lrmsg)
                                string MsgNO = this.InsertSysMsg(conn, DataTerminal, DataBody, "1", "M", (DataTerminalName == "G" ? DataGroup : ""), (DataTerminalName == "U" ? DataGroup : ""), DataGUID);
                                if (MsgNO.Length > 0)
                                {
                                    //系統將訊息轉發給群成員(以發送者的帳號) 
                                    base.SendGroupSysBroadcast("D", "1", "M", DataTerminal, DataGroup, DataBody, DataTerminalName, conn, DataGUID, MsgNO);
                                    // 轉發完再發回執
                                    // 向發送者發送回執7-03
                                    base.PushFeedback(DataGUID, MsgNO);

                                }
                                conn.CloseConnection();
                            }
                            catch
                            {
                                conn.CloseConnection();
                            }
                        }
                        #endregion

                        break;
                    case "M":
                        #region " 郵件訊息 "

                        //別搞暈了
                        //DataTerminal是發送人
                        //DataTerminalName是發送人姓名
                        //DataGroup是接收人
                        using (SQLHelper conn = new SQLHelper(m_asyncSocketServer.DBInfo))
                        {
                            conn.OpenConnection();
                            try
                            {
                                bool passed = true;
                                string errorCode = "";
                                //不能自己發給自己
                                if (DataTerminal == DataGroup)
                                {
                                    passed = false;
                                    errorCode = "04";
                                }
                                if (passed)
                                {
                                    //1.檢查發送人帳號是否有效(數據庫)
                                    if (conn.OpenDataTable("select uid from lrtduser (nolock) where user_no='" + DataTerminal + "'", CommandType.Text).Rows.Count == 0)
                                    {
                                        passed = false;
                                        errorCode = "04";
                                    }
                                    //2.檢查接收人帳號是否有效(數據庫)
                                    if (conn.OpenDataTable("select uid from lrtduser (nolock) where user_no='" + DataGroup + "'", CommandType.Text).Rows.Count == 0)
                                    {
                                        passed = false;
                                        errorCode = "05";
                                    }
                                }
                                //通過
                                if (passed)
                                {
                                    //3.記錄到數據庫中
                                    string MsgNO = this.InsertMsg(conn, DataTerminal, DataBody, "", DataGroup, "1", "", "4", "0", DataGUID, false, true);
                                    if (MsgNO.Length > 0)
                                    {
                                        //開始發送
                                        base.SendP2PMessage(DataTerminal, DataTerminalName, DataGroup, DataBody, conn, DataGUID, MsgNO, DataType);

                                        // 轉發完再發回執
                                        // 向發送者發送回執7-03
                                        base.PushFeedback(DataGUID, MsgNO);
                                    }
                                }
                                else
                                {
                                    #region " 通知Mail發送人有問題 "

                                    // 轉發完再發回執
                                    // 向發送者發送回執7-04 或 7-05
                                    base.PushMessage("", ParseProtocol.ConvertMsgToByte(errorCode, "7", "", "", "", DataGUID, ""), curUserID, m_asyncSocketServer.AppUserTokenList, "SendMail");

                                    #endregion
                                }
                                conn.CloseConnection();
                            }
                            catch
                            {
                                conn.CloseConnection();
                            }
                        }

                        #endregion

                        break;
                    case "P":
                        #region " APP發離線文件(郵件附件) "
                        if (DataGroup.Length > 0)
                        {
                            //不需要子類別:O, 只要是APP接入都認為是O.這樣把群號省出來放'發送人賬號'
                            string MsgNO = base.ProcessTransferFileRequest(DataGroup, DataType, DataTerminal, "O", DataGUID, DataBody, DataTerminalName);
                            // 向發送者發送回執7-03
                            base.PushFeedback(DataGUID, MsgNO);
                        }
                        #endregion

                        break;
                    case "V":
                        #region " 第三方設備數據顯示(不存數據庫) "

                        this.Send3rdPartDeviceData(DataGroup, DataGUID, DataBody);

                        #endregion

                        break;

                    case "W":
                        #region " 訂閱號消息 "

                        if (DataGroup.Length > 0)
                        {
                            //用戶向訂閱號發命令
                            SendRequestToSubService(DataTerminal, DataGroup, DataBody, DataTerminalName, DataGUID, false);
                        }

                        #endregion

                        break;
                }

                //把已處理的數據從緩存里清除
                //receiveBuffer.Clear(receiveBuffer.DataCount);
                receiveBuffer.Clear(msgDataLength);
                //扣除已發完的包
                base.m_readyPackage--;

                //發完一個包后,如果DataCount>0說明有粘包數據,嘗試發送出去,否則會影響後面數據的發送效率.
                //如果粘包不是一個完整的數據包就返回去接收數據
                if (base.m_readyPackage > 0)
                    return ProcessCommand(userToken);
                else
                    return true;
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog("AppProcessor.ProcessCommand", string.Format("執行用戶:{0}命令時時出錯:{1}.", curUserID, (ex != null ? ex.Message : "")));
                //主動關閉連接
                userToken.Closing = true;
                return false;
            }
        }