/// <summary> /// 線程執行體,登錄驗證 /// </summary> /// <param name="obj"></param> private void ThreadLoginCheckFunc(object objs) { if (objs != null) { //2016/02/27 object obj = ((List<object>)objs)[0]; // 用戶Socket object tobj = ((List<object>)objs)[1]; // 登錄線程 Thread LoginThread = (Thread)tobj; try { string UserID = ""; Socket newClient = obj as Socket; //返回解包后的資料(返回數組 0=type ; 1=終端; 2=群號; 3=時間; 4=消息ID; 5=消息內容; 6=終端姓名) // type = "0" 是PC登錄; type = "WS" 是Web登錄 object[] ReceiveData = ConvertMethod.ParseLoginData(newClient, LoginTimeOut); //ConvertMethod.UnMsgPackage(newClient); string DataType = ReceiveData[0].ToString(); string DataTerminal = ReceiveData[1].ToString(); //普通用戶登錄為空 //APP登錄為APP //訂閱號登錄為SUB(會有一個特別的HashTable來保存訂閱號的連接) string DataGroup = ReceiveData[2].ToString(); string DataTerminalName = ReceiveData[6].ToString(); string DataText = ReceiveData[5].ToString(); if (DataType == "0" && DataTerminal.Length > 0) { //test //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "PC端" + DataTerminal + "請求登錄"); //LogHelper.WriteLog("StartUp()", "PC端用戶: " + DataTerminal + "-" + DataTerminalName + " 請求登錄"); UserID = DataTerminal; // 用戶帳號 bool Passed = true; switch (DataGroup.ToUpper()) { case "SUB": #region " 訂閱號登錄 " //未開工2016/01/26 #endregion break; case "APP": #region " APP登錄 " try { List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, DataGroup, Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (newClient) { foreach (byte[] msg in msgs) { 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) { //創建連接對象 UserSocket AppUser = new UserSocket(); AppUser.ID = UserID; AppUser.Socket = newClient; AppUser.State = UserSocket.UserStates.Online; // 將新連接加入轉發表並創建線程為其服務 // Key-GUID永不重複 _app_transmit_tb.Add(UserID, AppUser); try { Thread clientThread = new Thread(new ParameterizedThreadStart(AppThreadFunc)); //加入哈希表 _app_thread_tb.Add(UserID, clientThread); clientThread.Start(UserID); } catch (Exception ex) { try { //清除已加入的連接 _app_transmit_tb.Remove(UserID); } catch { } //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():開啟新線程", "建立登入用戶新線程時:" + ex.Message); LogHelper.WriteLog("StartUp()", "建立登入用戶" + DataTerminal + "-" + DataTerminalName + "新線程時:" + (ex != null ? ex.Message : "")); } } #endregion break; case "MOBILE": LogHelper.WriteLog("ThreadLoginCheckFunc()", "發現非常進入者:" + DataTerminal); #region " 移動端登錄 " UserSocket MobileUser = _mobile_transmit_tb[DataTerminal] as UserSocket; if (MobileUser != null) { Socket curSkt = MobileUser.Socket; #region " 發送離線 " try { List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("00", "7", DataTerminal, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); //如果2秒內得不到之前登陸的對象,就直接干掉 //否則此帳號將永遠無法登錄 if (Monitor.TryEnter(curSkt, 2000)) { try { //向用戶本人發送離線 foreach (byte[] msg in msgs) { curSkt.Send(msg); //SendData(curSkt, msg); } } catch { } finally { Monitor.Exit(curSkt); } } else { //如果到這里說明之前登陸的對象已經死鎖 } UpdateUserLog(UserID, "1", "0", "因相同帳號再次登陸而強制離線."); //log //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "相同帳號再次登陸:" + DataTerminal + " " + DataTerminalName); //LogHelper.WriteLog("StartUp()", "相同帳號再次登陸:" + DataTerminal + " " + DataTerminalName); } catch (SocketException ex) { //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "轉發用戶" + UserID + "離線消息時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "轉發用戶" + UserID + "離線消息時:" + (ex != null ? ex.Message : "")); } try { if (curSkt.Connected) { curSkt.Shutdown(SocketShutdown.Both); //curSkt.Disconnect(false); } curSkt.Close(); curSkt = null; Thread thread = _mobile_thread_tb[DataTerminal] as Thread; if (thread != null) { thread.Abort(); //線程池不會被遍歷,不鎖. _mobile_thread_tb.Remove(DataTerminal); } lock (_transmit_tb.SyncRoot) _mobile_transmit_tb.Remove(DataTerminal); } catch (SocketException ex) { //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "嘗試關閉用戶" + DataTerminal + "線程和Socket連接時出錯." + (ex != null ? ex.Message : "")); LogHelper.WriteLog("ThreadLoginCheckFunc()", "嘗試關閉用戶" + DataTerminal + "線程和Socket連接時出錯." + (ex != null ? ex.Message : "")); } #endregion } // 驗證是否為唯一用戶 if (_mobile_transmit_tb.Count != 0 && _mobile_transmit_tb.ContainsKey(UserID)) { try { List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("登錄失敗.", "3", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (newClient) { foreach (byte[] msg in msgs) { newClient.Send(msg); //SendData(newClient, msg); } } //test //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "PC端" + DataTerminal + "登錄失敗"); LogHelper.WriteLog("ThreadLoginCheckFunc()", "移動客戶端" + DataTerminal + "登錄失敗"); } catch (SocketException ex) { //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():驗證是否為唯一用戶", "發送登陸失敗信息時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "發送登陸失敗信息時" + (ex != null ? ex.Message : "")); } } else { // 服務器開放登錄功能 try { List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, DataGroup, Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (newClient) { foreach (byte[] msg in msgs) { newClient.Send(msg); //SendData(newClient, msg); } } } catch (Exception ex) { Passed = false; //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():服務器開放登錄功能", "發送登陸成功信息時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "發送登錄成功信息時" + (ex != null ? ex.Message : "")); } if (Passed) { //創建連接對象 MobileUser = new UserSocket(); MobileUser.ID = UserID; MobileUser.Socket = newClient; MobileUser.State = UserSocket.UserStates.Online; //登錄時群號規則: 普通用戶登錄時為空格, 手機應用登錄時為"MOBILE" using (SQLHelper conn = new SQLHelper(DBInfo)) { conn.OpenConnection(); try { #region " 獲得當前用記的所有聯絡人并向他們推送用戶上線消息 " StateNotifyQueue.Enqueue(new List<object>() { MobileUser, "1" }); #endregion //Test //LogHelper.WriteLog("ThreadLoginCheckFunc()", User.ID + "推送未讀消息."); #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()); // 判斷個人消息還是群消息 List<byte[]> rtnMsgs = ConvertMethod.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) { 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'"); //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("ThreadLoginCheckFunc()", "標識歷史信息為已讀時:" + (ex != null ? ex.Message : "")); } } } //Test LogHelper.WriteLog("ThreadLoginCheckFunc()", "共向移動端用戶:" + MobileUser.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 = ConvertMethod.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) { 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("ThreadLoginCheckFunc()", "標識歷史系統消息為已讀時:" + (ex != null ? ex.Message : "")); } } } //Test //LogHelper.WriteLog("ThreadLoginCheckFunc()", "共向用戶:" + User.ID + "推送" + MsgsList.Rows.Count.ToString() + "條歷史命令."); } #endregion MsgsList.Dispose(); MsgsList = null; #endregion } catch (SocketException ex) { //test //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "向PC端" + DataTerminal + "推送未讀信息時出錯." + (ex != null ? ex.Message : "")); LogHelper.WriteLog("ThreadLoginCheckFunc()", "向PC端" + DataTerminal + "推送未讀信息和命令時出錯." + (ex != null ? ex.Message : "")); } //更新用戶狀態 try { DoUpdateUserLog(conn, UserID, "0", "0", "登錄"); DoUpdateUserState(conn, UserID, "1"); //上線中 } catch (Exception ex) { Passed = false; LogHelper.WriteLog("ThreadLoginCheckFunc()", "更新PC端用戶:" + DataTerminal + "狀態." + (ex != null ? ex.Message : "")); } conn.CloseConnection(); } if (Passed) { #region " 向移動端 客戶端推送平臺數據(在線人數等) - 暫不推送 " //try //{ // List<byte[]> MsgToPC = ConvertMethod.ConvertMsgToByte(string.Format(SysMessage, ActiveUsersCount, // OnlineUsersCount, // RegisteredUsersCount, // TodayMessagesCount, // TotalMessagesCount), // "9", "", "", "", "", ""); // //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 // lock (newClient) // { // foreach (byte[] msg in MsgToPC) // { // 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("ThreadLoginCheckFunc()", "向PC端" + DataTerminal + "推送平臺數據(在線人數等)." + (ex != null ? ex.Message : "")); //} #endregion } if (Passed) { // 將新連接加入轉發表並創建線程為其服務 lock (_mobile_transmit_tb.SyncRoot) { _mobile_transmit_tb.Add(UserID, MobileUser); } try { Thread clientThread = new Thread(new ParameterizedThreadStart(MobileThreadFunc)); //加入哈希表 _mobile_thread_tb.Add(UserID, clientThread); //clientThread.Start(userName); clientThread.Start(UserID); } catch (Exception ex) { try { // 發生錯誤時移除連接 lock (_mobile_transmit_tb.SyncRoot) { //_transmit_tb.Add(UserID, newClient); _mobile_transmit_tb.Remove(UserID); } } catch { } //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():開啟新線程", "建立登入用戶新線程時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "建立登入用戶" + DataTerminal + "-" + DataTerminalName + "新線程時:" + (ex != null ? ex.Message : "")); } } } } #endregion break; case "FILE": #region " 文件傳送帳號登錄 " Passed = true; //try //{ // List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, DataGroup, Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); // //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 // lock (newClient) // { // foreach (byte[] msg in msgs) // { // newClient.Send(msg); // } // } //} //catch (Exception ex) //{ // Passed = false; // //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():服務器開放登錄功能", "發送登陸成功信息時:" + ex.Message); // LogHelper.WriteLog("StartUp()", "發送登錄成功信息時" + (ex != null ? ex.Message : "")); //} if (Passed) { //創建連接對象 UserSocket AppUser = new UserSocket(); AppUser.ID = UserID; AppUser.Socket = newClient; AppUser.State = UserSocket.UserStates.Online; AppUser.Type = "F"; AppUser.SenderID = DataText.Split(new char[] { '|' })[0].Trim(); AppUser.ReceiverID = DataText.Split(new char[] { '|' })[1].Trim(); // 將新連接加入轉發表並創建線程為其服務 // Key-GUID永不重複 _file_transmit_tb.Add(UserID, AppUser); try { // 2016/02/22 // 接收者只能接收數據,不需要開啟Server-Reveived線程 if (UserID.Substring(UserID.Length - 1, 1) != "R") { Thread clientThread = new Thread(new ParameterizedThreadStart(FileThreadFunc)); //加入哈希表 _file_thread_tb.Add(UserID, clientThread); clientThread.Start(UserID); } else { //接收者已經登錄.找到S通道的發送者并向他發送允許建立T通道的通知. //發送者ID-接收者ID-GUID-R/S中第一個為對方的S通道帳號 //string SenderID = UserID.Substring(0, 50).Trim(); //string SenderGUID = UserID.Substring(51, 32).Trim(); string SenderGUID = UserID.Substring(0, UserID.Length - 2).Trim(); //缺異常處理.報錯后必須將接收者的T通道關閉 string MsgNO = ProcessTransferFileRequest("P", AppUser.SenderID, "P", AppUser.SenderID, "R", SenderGUID, "FILE", "RECEIVER"); if (MsgNO.Length == 0) { try { if (AppUser.Socket.Connected) { AppUser.Socket.Shutdown(SocketShutdown.Both); } AppUser.Socket.Close(); //LogHelper.WriteLog("StartUp()", "無效登錄請求被丟棄"); } catch { } try { //清除已加入的連接 _file_transmit_tb.Remove(UserID); } catch { } } } } catch (Exception ex) { try { //清除已加入的連接 _file_transmit_tb.Remove(UserID); } catch { } //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():開啟新線程", "建立登入用戶新線程時:" + ex.Message); LogHelper.WriteLog("StartUp()", "建立登入用戶" + DataTerminal + "-" + DataTerminalName + "新線程時:" + (ex != null ? ex.Message : "")); } } #endregion break; default: #region " PC端登錄 " UserSocket User = _transmit_tb[DataTerminal] as UserSocket; if (User != null) { Socket curSkt = User.Socket; #region " 發送離線 " try { List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("00", "7", DataTerminal, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); //如果2秒內得不到之前登陸的對象,就直接干掉 //否則此帳號將永遠無法登錄 if (Monitor.TryEnter(curSkt, 2000)) { try { //向用戶本人發送離線 foreach (byte[] msg in msgs) { curSkt.Send(msg); //SendData(curSkt, msg); } } catch { } finally { Monitor.Exit(curSkt); } } else { //如果到這里說明之前登陸的對象已經死鎖 } //lock (curSkt) //{ // //向用戶本人發送離線 // foreach (byte[] msg in msgs) // { // curSkt.Send(msg); // } //} UpdateUserLog(UserID, "1", "0", "因相同帳號再次登陸而強制離線."); //log //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "相同帳號再次登陸:" + DataTerminal + " " + DataTerminalName); //LogHelper.WriteLog("StartUp()", "相同帳號再次登陸:" + DataTerminal + " " + DataTerminalName); } catch (SocketException ex) { //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "轉發用戶" + UserID + "離線消息時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "轉發用戶" + UserID + "離線消息時:" + (ex != null ? ex.Message : "")); } try { if (curSkt.Connected) { curSkt.Shutdown(SocketShutdown.Both); //curSkt.Disconnect(false); } curSkt.Close(); curSkt = null; Thread thread = _thread_tb[DataTerminal] as Thread; if (thread != null) { thread.Abort(); //線程池不會被遍歷,不鎖. _thread_tb.Remove(DataTerminal); } lock (_transmit_tb.SyncRoot) _transmit_tb.Remove(DataTerminal); } catch (SocketException ex) { //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "嘗試關閉用戶" + DataTerminal + "線程和Socket連接時出錯." + (ex != null ? ex.Message : "")); LogHelper.WriteLog("ThreadLoginCheckFunc()", "嘗試關閉用戶" + DataTerminal + "線程和Socket連接時出錯." + (ex != null ? ex.Message : "")); } #endregion } // 驗證是否為唯一用戶 if (_transmit_tb.Count != 0 && _transmit_tb.ContainsKey(UserID)) { try { List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("登錄失敗.", "3", UserID, DataTerminalName, "", Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (newClient) { foreach (byte[] msg in msgs) { newClient.Send(msg); //SendData(newClient, msg); } } //test //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "PC端" + DataTerminal + "登錄失敗"); LogHelper.WriteLog("ThreadLoginCheckFunc()", "PC端" + DataTerminal + "登錄失敗"); } catch (SocketException ex) { //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():驗證是否為唯一用戶", "發送登陸失敗信息時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "發送登陸失敗信息時" + (ex != null ? ex.Message : "")); } } else { // 服務器開放登錄功能 try { List<byte[]> msgs = ConvertMethod.ConvertMsgToByte("登錄成功.", "2", UserID, DataTerminalName, DataGroup, Guid.NewGuid().ToString().Replace("-", "").ToUpper(), ""); //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (newClient) { foreach (byte[] msg in msgs) { newClient.Send(msg); //SendData(newClient, msg); } } } catch (Exception ex) { Passed = false; //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():服務器開放登錄功能", "發送登陸成功信息時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "發送登錄成功信息時" + (ex != null ? ex.Message : "")); } if (Passed) { //創建連接對象 User = new UserSocket(); User.ID = UserID; User.Socket = newClient; User.State = UserSocket.UserStates.Online; //登錄時群號規則: 普通用戶登錄時為空格, 外接應用(APP)登錄時為"APP" #region " 普通用戶才做以下操作 " if (DataGroup.Length == 0) { 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()); // } // //2016/02/27 // //For Test // //改為獨立線程來發,讓用戶登錄不受影響 // //如果此聯絡人在線就通知他(她)當前用戶上線了 // try // { // Thread stateThread = new Thread(new ParameterizedThreadStart(StateNotifyThreadFunc)); // stateThread.Start(User); // } // catch // { } // //SendUserState(User); //} //ContactsList.Dispose(); //ContactsList = null; #endregion //Test //LogHelper.WriteLog("ThreadLoginCheckFunc()", User.ID + "推送未讀消息."); #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()); // 判斷個人消息還是群消息 List<byte[]> rtnMsgs = ConvertMethod.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) { 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'"); //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("ThreadLoginCheckFunc()", "標識歷史信息為已讀時:" + (ex != null ? ex.Message : "")); } } } //Test LogHelper.WriteLog("ThreadLoginCheckFunc()", "共向用戶:" + User.ID + "推送" + MsgsList.Rows.Count.ToString() + "條歷史未讀消息."); } #endregion #region " 命令(取消推送) " //MsgsList = GetUnreadMsgs(conn, UserID, "C"); //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["cmd_no"].ToString())) // MaxMsgNO = long.Parse(UnreadMsg["cmd_no"].ToString()); // // 發給登錄人 // DateTime MsgDT = DateTime.Parse(UnreadMsg["cmd_date"].ToString() + " " + UnreadMsg["cmd_time"].ToString()); // // 判斷個人消息還是群消息 // List<byte[]> rtnMsgs = ConvertMethod.ConvertMsgToByte(UnreadMsg["cmd_text"].ToString(), // "C", // UnreadMsg["cmd_user"].ToString(), // UnreadMsg["user_name"].ToString(), // UnreadMsg["td_no"].ToString(), // MsgDT, // UnreadMsg["cmd_guid"].ToString(), // UnreadMsg["cmd_no"].ToString()); // //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 // lock (newClient) // { // foreach (byte[] msg in rtnMsgs) // { // newClient.Send(msg); // //SendData(newClient, msg); // } // } // } // // 更新為已讀 // try // { // MarkReadHistoryMsgQueue.Enqueue("update a set a.cmd_state='1' from lrcmdstate a where a.cmd_no<=" + MaxMsgNO.ToString() + " and a.cmd_to='" + UserID + "' and a.cmd_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("ThreadLoginCheckFunc()", "標識歷史命令為已讀時:" + (ex != null ? ex.Message : "")); // } // } // } // //Test // LogHelper.WriteLog("ThreadLoginCheckFunc()", "共向用戶:" + User.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 = ConvertMethod.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) { 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("ThreadLoginCheckFunc()", "標識歷史系統消息為已讀時:" + (ex != null ? ex.Message : "")); } } } //Test //LogHelper.WriteLog("ThreadLoginCheckFunc()", "共向用戶:" + User.ID + "推送" + MsgsList.Rows.Count.ToString() + "條歷史命令."); } #endregion MsgsList.Dispose(); MsgsList = null; #endregion } catch (SocketException ex) { //test //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp()", "向PC端" + DataTerminal + "推送未讀信息時出錯." + (ex != null ? ex.Message : "")); LogHelper.WriteLog("ThreadLoginCheckFunc()", "向PC端" + DataTerminal + "推送未讀信息和命令時出錯." + (ex != null ? ex.Message : "")); } //更新用戶狀態 try { DoUpdateUserLog(conn, UserID, "0", "0", "登錄"); DoUpdateUserState(conn, UserID, "1"); //上線中 } catch (Exception ex) { Passed = false; LogHelper.WriteLog("ThreadLoginCheckFunc()", "更新PC端用戶:" + DataTerminal + "狀態." + (ex != null ? ex.Message : "")); } conn.CloseConnection(); } if (Passed) { #region " 向PC客戶端推送平臺數據(在線人數等) " try { List<byte[]> MsgToPC = ConvertMethod.ConvertMsgToByte(string.Format(SysMessage, ActiveUsersCount, OnlineUsersCount, RegisteredUsersCount, TodayMessagesCount, TotalMessagesCount), "9", "", "", "", "", ""); //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (newClient) { foreach (byte[] msg in MsgToPC) { 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("ThreadLoginCheckFunc()", "向PC端" + DataTerminal + "推送平臺數據(在線人數等)." + (ex != null ? ex.Message : "")); } #endregion } } #endregion if (Passed) { // 將新連接加入轉發表並創建線程為其服務 lock (_transmit_tb.SyncRoot) { //_transmit_tb.Add(UserID, newClient); _transmit_tb.Add(UserID, User); } try { Thread clientThread = new Thread(new ParameterizedThreadStart(ThreadFunc)); //加入哈希表 _thread_tb.Add(UserID, clientThread); //clientThread.Start(userName); clientThread.Start(UserID); } catch (Exception ex) { try { // 發生錯誤時移除連接 lock (_transmit_tb.SyncRoot) { //_transmit_tb.Add(UserID, newClient); _transmit_tb.Remove(UserID); } } catch { } //clsClientLog.WriteLog(clsClientLog.LogType.Error, "StartUp():開啟新線程", "建立登入用戶新線程時:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc()", "建立登入用戶" + DataTerminal + "-" + DataTerminalName + "新線程時:" + (ex != null ? ex.Message : "")); } } } } #endregion break; } } else if (DataType == "WS" && DataTerminal.Length > 0) { //LogHelper.WriteLog("StartUp()", "手機端用戶: " + DataTerminal + "-" + DataTerminalName + " 請求登錄"); #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 } else { // 無效訊息-丟棄 try { if (newClient.Connected) { newClient.Shutdown(SocketShutdown.Both); //clientSkt.Disconnect(false); } newClient.Close(); //LogHelper.WriteLog("StartUp()", "無效登錄請求被丟棄"); } catch (SocketException ex) { //clsClientLog.WriteLog(clsClientLog.LogType.System, "CloseClientSocket", "嘗試關閉一個異常的Socket連接時出現問題:" + ex.Message); LogHelper.WriteLog("ThreadLoginCheckFunc", "嘗試關閉一個無法識別的Socket連接請求時出現問題:" + (ex != null ? ex.Message : "")); } } } catch (Exception ex) { LogHelper.WriteLog("ThreadLoginCheckFunc", "用戶登錄時發生錯誤:" + (ex != null ? ex.Message : "")); } finally { // 2016/02/27 // 回收到隊列 LoginThreadsQueue.Enqueue(LoginThread); //LogHelper.WriteLog("ThreadLoginCheckFunc", "回收登錄線程[" + LoginThread.ManagedThreadId.ToString() + "]"); } } ////需不需要干掉自己? //try //{ // Thread.CurrentThread.Abort(); //} //catch //{ } }
/// <summary> /// 發送用戶狀態 /// </summary> /// <param name="User"></param> /// <param name="UserState"></param> private void SendUserState(UserSocket User, string UserState) { if (_transmit_tb == null) return; if (User == null) return; if (User.Contacts.Count > 0) { try { //0=空閒|1=上線|2=離開|3=忙碌|4=不要打擾|5=隱身|6=離線|7=簽名 //List<byte[]> msgs = ConvertMethod.ConvertMsgToByte(User.Signature, "S", User.ID, (User.ChangeSignature ? "7" : ((int)User.State).ToString()), "", "", ""); List<byte[]> msgs = ConvertMethod.ConvertMsgToByte(User.Signature, "S", User.ID, UserState, "", "", ""); //Test //LogHelper.WriteLog("SendUserState", "準備把" + User.ID + "的狀態" + UserState + "推送給聯絡人..."); int count = 0; foreach (string contactID in User.Contacts) { //防止自己是自己的好友,給自己發狀態 #region " PC端用戶 " if (_transmit_tb.ContainsKey(contactID) && contactID != User.ID) { //PC用戶 try { UserSocket Contact = _transmit_tb[contactID] as UserSocket; //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 if (Contact != null) { if (Contact.Socket != null) { if (Contact.Socket.Connected) { lock (Contact.Socket) { //Test //3秒不發不出去就跳過 Contact.Socket.SendTimeout = 3000; try { foreach (byte[] msg in msgs) { Contact.Socket.Send(msg); //SendData(Contact.Socket, msg); } count++; } catch (SocketException ex) { throw ex; } finally { Contact.Socket.SendTimeout = 0; } } } } } } catch (SocketException ex) { // 可能掉線了,放他一馬. LogHelper.WriteLog("SendUserState", "向聯絡人:" + contactID + "發送登錄用戶" + User.ID + "的狀態時出現問題." + (ex != null ? ex.Message : "")); } } #endregion #region " Mobile端用戶 " if (_mobile_transmit_tb.ContainsKey(contactID) && contactID != User.ID) { //Mobile用戶 try { UserSocket Contact = _mobile_transmit_tb[contactID] as UserSocket; //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 if (Contact != null) { if (Contact.Socket != null) { if (Contact.Socket.Connected) { lock (Contact.Socket) { //Test //3秒不發不出去就跳過 Contact.Socket.SendTimeout = 3000; try { foreach (byte[] msg in msgs) { Contact.Socket.Send(msg); //SendData(Contact.Socket, msg); } count++; } catch (SocketException ex) { throw ex; } finally { Contact.Socket.SendTimeout = 0; } } } } } } catch (SocketException ex) { // 可能掉線了,放他一馬. LogHelper.WriteLog("SendUserState", "向聯絡人:" + contactID + "發送登錄用戶" + User.ID + "的狀態時出現問題." + (ex != null ? ex.Message : "")); } } #endregion //else if (_ws_transmit_tb.ContainsKey(contactID)) //{ // //手機用戶 //} } //Test //LogHelper.WriteLog("SendUserState", "成功向" + count.ToString() + "位聯絡人推送了" + User.ID + "的狀態:" + UserState); //if(User.ChangeSignature) // User.ChangeSignature = false; //復位 } catch { } } }
private void ProcessWebUserState(UserSocket User) { if (User == null) return; using (SQLHelper conn = new SQLHelper(DBInfo)) { conn.OpenConnection(); try { //通知在線的聯絡人當前用戶改變了狀態 User.SetUserState("6"); DoUpdateUserLog(conn, User.ID, "1", "1", "Mobile端登出"); //如果PC端沒在線就通知聯絡人此人離線了 UserSocket PCUser = _transmit_tb[User.ID] as UserSocket; if (PCUser == null) { StateNotifyQueue.Enqueue(new List<object>() { User, ((int)User.State).ToString() }); //SendUserState(User); //改為獨立線程來發 //如果此聯絡人在線就通知他(她)當前用戶上線了 //try //{ // Thread stateThread = new Thread(new ParameterizedThreadStart(StateNotifyThreadFunc)); // stateThread.Start(User); //} //catch //{ } DoUpdateUserState(conn, User.ID, "6"); //離線 } conn.CloseConnection(); } catch { conn.CloseConnection(); } } }