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; }
/// <summary> /// 執行狀態推送 /// </summary> /// <param name="msgs"></param> /// <param name="MsgTo"></param> /// <param name="UserTokenList"></param> /// <returns></returns> private void PushUserState(List<byte[]> msgs, string MsgTo, SocketUserTokenList UserTokenList, int SendTimeout) { SocketUserToken recUser = UserTokenList[MsgTo] as SocketUserToken; if (recUser != null) { Socket userSkt = recUser.ConnectSocket; try { if (userSkt.Connected) { //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (userSkt) { //Test:異步發送暫時不設置SendTimeout //3秒不發不出去就跳過 //userSkt.SendTimeout = SendTimeout; try { foreach (byte[] msg in msgs) { //2016/05/19 test recUser.AsyncSendAgent.DoSendBuffer(msg); //userSkt.Send(msg); //SendData(userSkt, msg); } } catch (SocketException ex) { throw ex; } finally { //userSkt.SendTimeout = 0; } } } } catch (SocketException ex) { throw ex; } } }
/// <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; }
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); }
/// <summary> /// 處理漫遊 /// </summary> /// <param name="Sender"></param> /// <param name="msgs"></param> /// <param name="UserTokenList"></param> private void PushRoaming(string Sender, List<byte[]> msgs, SocketUserTokenList UserTokenList) { SocketUserToken recUser = UserTokenList[Sender] as SocketUserToken; if (recUser != null) { Socket userSkt = recUser.ConnectSocket; // 系統將訊息轉發給群成員(以發送者的帳號) //問題: 1.只有帳號沒有姓名.Client無法顯示姓名 // 2.沒有發送日期和時間 try { //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (userSkt) { foreach (byte[] msg in msgs) { //2016/05/19 test recUser.AsyncSendAgent.DoSendBuffer(msg); //userSkt.Send(msg); //SendData(userSkt, msg); } } } catch (SocketException ex) { try { LogHelper.WriteLog("PushRoaming", "漫遊發群消息給用戶:" + Sender + "時發生異常,斷開連接." + (ex != null ? ex.Message : "")); //主動關閉連接 //recUser.Closing = true; //掉線了,直接干掉. m_asyncSocketServer.CloseClientSocket(recUser); } catch { } } } }
/// <summary> /// 執行消息推送 /// </summary> /// <param name="Users"></param> /// <param name="msgs"></param> /// <param name="MsgTo"></param> /// <param name="UserTokenList"></param> /// <returns></returns> protected string PushMessage(string Users, List<byte[]> msgs, string MsgTo, SocketUserTokenList UserTokenList, string CommandDesc) { SocketUserToken recUser = UserTokenList[MsgTo] as SocketUserToken; if (recUser != null) { Socket userSkt = recUser.ConnectSocket; try { if (userSkt.Connected) { //鎖住線程,保證本次發送完成後其他線程才能對此用戶發送消息 lock (userSkt) { foreach (byte[] msg in msgs) { //2016/05/19 test recUser.AsyncSendAgent.DoSendBuffer(msg); //userSkt.Send(msg); //SendData(userSkt, msg); } } Users += "'" + MsgTo + "',"; } else { LogHelper.WriteLog(CommandDesc + ".PushMessage", "用戶:" + MsgTo + "已斷開連接(Socket.Connected為false)."); //主動關閉連接 //recUser.Closing = true; //掉線了,直接干掉. m_asyncSocketServer.CloseClientSocket(recUser); } } catch (SocketException ex) { try { LogHelper.WriteLog(CommandDesc + ".PushMessage", "用戶:" + MsgTo + "異常斷開連接:" + (ex != null ? ex.Message : "")); //主動關閉連接 //recUser.Closing = true; //掉線了,直接干掉. m_asyncSocketServer.CloseClientSocket(recUser); } catch { } } } //else //{ // LogHelper.WriteLog(CommandDesc + ".PushMessage", "用戶:" + MsgTo + "不存在或未登錄."); //} return Users; }
/// <summary> /// 得到指定客戶端的在線用戶清單 /// </summary> /// <param name="UserTokenList"></param> /// <returns></returns> private string GetOnlineUserList(SocketUserTokenList UserTokenList) { string UserList = ""; lock (UserTokenList.SyncRoot) { foreach (DictionaryEntry de in UserTokenList.Table) { UserList += de.Key.ToString() + ","; } } return UserList; }