/* Sog 游戏基础库 2016 by zouwei */ using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography.X509Certificates; using Sog; using Sog.Crypto; using Sog.Gate; using Sog.IO; using Sog.Log; namespace Gate { public class GateClientService : BaseReloadableService { private ServerApp m_app; ClientServiceData m_data; private object m_clientDictLocker = new object(); private object m_needCloseClientsLocker = new object(); private long m_lastNotifyBackEndClientCountTimeMs = 0; private int ZipClientMsgSize; //接口实现 public override int GetServiceType() { return GateServiceType.GateClientService; } //接口实现 public override void Dispose() { //反注册消息处理,必须做这一步,否则内存泄漏,对象无法引用各种错误 m_data.m_socketListener.DataReceived -= socketListener_DataReceived; m_data.m_socketListener.Connected -= socketListener_OnTcpConnectCompleted; m_data.m_socketListener.Disconnected -= socketListener_Disconnected; if (m_data.m_udpListener != null) { m_data.m_udpListener.DataReceived -= socketListener_DataReceived; m_data.m_udpListener.Connected -= socketListener_OnUdpConnectCompleted; m_data.m_udpListener.Disconnected -= socketListener_Disconnected; } if (m_data.m_webSessionListener != null) { m_data.m_webSessionListener.DataReceived -= socketListener_DataReceived; m_data.m_webSessionListener.Connected -= socketListener_OnWebSocketConnectCompleted; m_data.m_webSessionListener.Disconnected -= socketListener_Disconnected; } m_app = null; m_data = null; } public GateClientService(ServerApp app) { m_app = app; m_data = ServerDataObjMgr.GetDataObj(GateDataObjType.ClientServiceData); InitTCPListener(); // InitWebSocketListener(); InitUDPListener(); } private void InitUDPListener() { if (m_data.m_udpListener == null) { m_data.m_socketSetting = new SessionSettings(10, 10, 10, 128000, GateServerUtils.GetServerConfig().listenport +1); m_data.m_udpListener = new UdpListener(m_data.m_socketSetting, "GateClientUdpListener"); m_data.m_udpListener.DataReceived += socketListener_DataReceived; m_data.m_udpListener.Connected += socketListener_OnUdpConnectCompleted; m_data.m_udpListener.Disconnected += socketListener_Disconnected; } } private void InitTCPListener() { if (m_data.m_socketListener == null) { SessionNetSelectMode nsMode = SessionNetSelectMode.Asynchronous; string clusterNetmode = m_app.GetCluster().GetAppParamByKey("netmode"); var config = GateServerUtils.GetServerConfig(); m_app.GetCluster().SetNetMode(config.netMode); if (config.netMode == 1) { nsMode = SessionNetSelectMode.Synchronous; } if (config.netMode == 0) { nsMode = clusterNetmode == "1" ? SessionNetSelectMode.Synchronous : SessionNetSelectMode.Asynchronous; } TraceLog.Debug("GateClientService.GateClientService netmode SessionNetSelectMode is {0}", nsMode); m_data.m_socketSetting = new SessionSettings(10, 10, 10, 128000, GateServerUtils.GetServerConfig().listenport); m_data.m_socketListener = new SessionListener(m_app, m_data.m_socketSetting, "GateClientListener", nsMode); if (nsMode == SessionNetSelectMode.Asynchronous) { TraceLog.Debug("GateClientService.GateClientService config.maxAsyncRecursionCount : {0}", config.maxAsyncRecursionCount); m_data.m_socketListener.SetMaxAsyncRecursionCount(config.maxAsyncRecursionCount); } } //注册消息处理 m_data.m_socketListener.DataReceived += socketListener_DataReceived; m_data.m_socketListener.Connected += socketListener_OnTcpConnectCompleted; m_data.m_socketListener.Disconnected += socketListener_Disconnected; } private void InitWebSocketListener() { TraceLog.Debug("GateClientService.InitWebSocketListener "); if (m_data.m_webSessionListener == null) { SessionNetSelectMode nsMode = SessionNetSelectMode.Asynchronous; string clusterNetmode = m_app.GetCluster().GetAppParamByKey("netmode"); var config = GateServerUtils.GetServerConfig(); m_app.GetCluster().SetNetMode(config.netMode); if (config.netMode == 1) { nsMode = SessionNetSelectMode.Synchronous; } if (config.netMode == 0) { nsMode = clusterNetmode == "1" ? SessionNetSelectMode.Synchronous : SessionNetSelectMode.Asynchronous; } TraceLog.Debug($"GateClientService.InitWebSocketListener {nsMode}"); var serverConfig = GateServerUtils.GetServerConfig(); m_data.m_socketSetting = new SessionSettings(10, 10, 10, 128000, serverConfig.websocketport); m_data.m_webSessionListener = new WebSessionListener(m_app, m_data.m_socketSetting, "GateWebClientListener", nsMode); if (serverConfig.websocketSecure) { TraceLog.Debug($"GateClientService.InitWebSocketListener open wss"); X509Certificate2 cert = new X509Certificate2(serverConfig.certificatePath, serverConfig.certificatePassword); m_data.m_webSessionListener.SetSchemeAndCertificate(true, cert); } else { m_data.m_webSessionListener.SetSchemeAndCertificate(false); } if (nsMode == SessionNetSelectMode.Asynchronous) { m_data.m_webSessionListener.SetMaxAsyncRecursionCount(config.maxAsyncRecursionCount); } } if (m_data.m_webSessionListener != null) { m_data.m_webSessionListener.DataReceived += socketListener_DataReceived; m_data.m_webSessionListener.Connected += socketListener_OnWebSocketConnectCompleted; m_data.m_webSessionListener.Disconnected += socketListener_Disconnected; } } public void CloseListen() { m_data = ServerDataObjMgr.GetDataObj(GateDataObjType.ClientServiceData); m_data.m_socketListener.Close(); m_data.m_udpListener?.Close(); m_data.m_webSessionListener?.Close(); } public void SetZipMsgSize(int size) { TraceLog.Trace("GateClientService.SetZipMsgSize {0}", size); ZipClientMsgSize = size; } public void StartListen() { m_data.m_lastCheckTimeoutTime = m_app.GetTimeSecond(); m_data.m_socketListener?.StartListen(true); //先取消upd m_data.m_udpListener?.StartListen(); // m_data.m_webSessionListener?.StartListen(true); } public int GetClientCount() { return m_data.m_clientsDict.Count; } private void socketListener_OnTcpConnectCompleted(object sender, SessionEventArgs e) { try { long sessionID = Sog.Service.GateSessionID.GenNextID(m_app.ServerID); e.Session.ResetSessionID(sessionID); e.Session.SetSocketBufferSize(128000); socketListener_OnConnectCompleted(sender, e); } catch (Exception ex) { TraceLog.Error("socketListener_OnTcpConnectCompleted error:{0}", ex); } } private void socketListener_OnUdpConnectCompleted(object sender, SessionEventArgs e) { try { long sessionID = Sog.Service.GateSessionID.GenNextID(m_app.ServerID); e.Session.ResetSessionID(sessionID); socketListener_OnConnectCompleted(sender, e); // debug if (e.Session is UdpSession udpSession) { TraceLog.Trace("socketListener_OnUdpConnectCompleted conv {0} session {1}" , udpSession.GetKcpConvId(), udpSession.SessionID); } else { TraceLog.Error("socketListener_OnUdpConnectCompleted session {0} not UdpSession" , e.Session.SessionID); } } catch (Exception ex) { TraceLog.Error("socketListener_OnUdpConnectCompleted error:{0}", ex); } } private void socketListener_OnWebSocketConnectCompleted(object sender, SessionEventArgs e) { try { long sessionID = Sog.Service.GateSessionID.GenNextID(m_app.ServerID); e.Session.ResetSessionID(sessionID); // debug if (e.Session is WebSession webSession) { TraceLog.Trace("socketListener_OnWebSocketConnectCompleted session {0}" , webSession.SessionID); } else { TraceLog.Error("socketListener_OnTcpConnectCompleted session {0} not UdpSession" , e.Session.SessionID); } socketListener_OnConnectCompleted(sender, e); } catch (Exception ex) { TraceLog.Error("socketListener_OnWebSocketConnectCompleted error:{0}", ex); } } private void socketListener_Disconnected(object sender, SessionEventArgs e) { try { long sessionID = e.Session.SessionID; TraceLog.Trace("socketListener_Disconnected session {0} disconneted ,notify to server", sessionID); AddToNeedCloseClient(e.Session.SessionID); } catch (Exception err) { TraceLog.Error("socketListener_Disconnected Disconnected error:{0}", err); } } private void socketListener_OnConnectCompleted(object sender, SessionEventArgs e) { try { long sessionID = e.Session.SessionID; e.Session.WriteSendRecvLog = true; GateClientInfo info = new GateClientInfo(m_app.GetTimeSecond(), e.Session); //wait server ack info.State = GameClientState.WaitServerAck; lock (m_clientDictLocker) { m_data.m_clientsDict.Add(sessionID, info); //加入等待队列 m_data.m_waitServerAckDict.Add(sessionID, info); m_data.m_waitClientPublicKeyDict.Add(sessionID, info); } string ip = "0.0.0.0"; if(e.Session.RemoteEndPoint != null) { try { ip = e.Session.RemoteEndPoint.ToString().Split(':')[0]; } catch(Exception) { } } if(e.Session is WebSession) { ip = ((WebSession)(e.Session)).clientIp; } TraceLog.Trace("socketListener_OnConnectCompleted session {0} ip {1} conneted, notify to server", sessionID, ip); GateClientConnectedReq req = new GateClientConnectedReq(); req.IPAddress = ip; GateServerUtils.GetServerMsgTrans().NotifyServerClientConnected(info, req); } catch (Exception err) { TraceLog.Error("socketListener_OnConnectCompleted ConnectCompleted error:{0}", err); } } private void socketListener_DataReceived(object sender, SessionEventArgs e) { try { long sessionID = e.Session.SessionID; int messageID = e.Message.Header.Type; GateServerConfig configInfo = GateServerUtils.GetServerConfig(); GateClientInfo info = GetGateClientInfoThreadSafe(sessionID); if (info == null) { TraceLog.Trace("socketListener_DataReceived session {0} no GateClientInfo", sessionID); return; } if (configInfo.checkSeq) { ushort recvSeq = (ushort)(e.Message.Header.ServerID >> 16); //检查seq if (recvSeq != info.RecvSeq + 1) { TraceLog.Error("socketListener_DataReceived session {0}, seq {1} invalid last recv seq {2}" , sessionID, recvSeq, info.RecvSeq); AddToNeedCloseClient(info.SessionID); return; } info.RecvSeq++; ushort recvCrc = (ushort)(e.Message.Header.ServerID & 0xFFFF); ushort crcValue = 0; if (e.Message.Buffer.Data != null && e.Message.Buffer.Length > 0) { crcValue = CRC.CRC16(e.Message.Buffer.Data, e.Message.Buffer.Length); } if(recvCrc != crcValue) { TraceLog.Error("socketListener_DataReceived session {0}, calc crc {1} != recv crc {2}" , sessionID, crcValue, recvCrc); AddToNeedCloseClient(info.SessionID); return; } } //检查流量 if (configInfo.checkFlow) { GateServerUtils.OnAddOneMessage(info, configInfo, messageID, 1, e.Message.Header.Length); if (info.FlowCheckInfo.aboveLimitTimes >= configInfo.maxLimitTimes) { if (configInfo.messageIgnoreLimitList == null || !configInfo.messageIgnoreLimitList.Contains(messageID)) { TraceLog.Error("socketListener_DataReceived session:{0}, flow limit:{1}__{2} messageId={3}" , sessionID, info.FlowCheckInfo.aboveLimitTimes, configInfo.maxLimitTimes,messageID); AddToNeedCloseClient(info.SessionID); return; } } } if (messageID == (int)SpecialMessageType.PublicKey) { TraceLog.TraceDetail("socketListener_DataReceived session {0} recv data len {1}, Type PublicKey" , sessionID, e.Message.Header.Length); OnRecvClientPublicKey(info, sessionID, e.Message); } else { TraceLog.TraceDetail("socketListener_DataReceived session {0} recv data len {1}, msg {2} trans to server" , sessionID, e.Message.Header.Length, messageID); //需要解密,空消息不解密 if(info.TeaKey != null && e.Message.Buffer.Data != null && e.Message.Buffer.Length > 0) { //解密有可能失败,需要try cache,要不然会丢很多消息 try { SogFastXTEA.Decrypt(e.Message.Buffer.Data, e.Message.Buffer.Length, info.TeaKey); GateServerUtils.GetServerMsgTrans().TransClientMessageToServer(info, e.Message); } catch (Exception ex) { TraceLog.Error("socketListener_DataReceived decrypt msg data failed! session {0} MsgType {1}" , sessionID, messageID); TraceLog.Exception(ex); } } else { GateServerUtils.GetServerMsgTrans().TransClientMessageToServer(info, e.Message); } } } catch (Exception ex) { TraceLog.Error("GateClientService.socketListener_DataReceived recv to Host:{0} error:{1}", e.Session.RemoteEndPoint, ex); } finally { e.Message.FreeData(); } } public GateClientInfo GetGateClientInfoThreadSafe(long sessionID) { GateClientInfo info; lock (m_clientDictLocker) { m_data.m_clientsDict.TryGetValue(sessionID, out info); } if (info == null) { TraceLog.Trace("GateClientService.GetGateClientInfoThreadSafe session {0} no GateClientInfo", sessionID); return null; } return info; } public void Update(long nowMs) { int maxClient = GateServerUtils.GetServerConfig().maxClientCount; bool isLimit = maxClient > 0 && m_data.m_clientsDict.Count >= maxClient; if (m_data.m_socketListener != null && m_data.m_socketListener.AcceptLimited != isLimit) { m_data.m_socketListener.AcceptLimited = isLimit; } if (m_data.m_webSessionListener != null && m_data.m_webSessionListener.AcceptLimited != isLimit) { m_data.m_webSessionListener.AcceptLimited = isLimit; } m_data.m_socketListener?.UpdateAccept(); m_data.m_socketListener?.UpdateAcceptedSessions(nowMs); m_data.m_webSessionListener?.UpdateAccept(); m_data.m_webSessionListener?.UpdateAcceptedSessions(nowMs); m_data.m_udpListener?.Update(nowMs); CheckTimeoutClient(); CloseNeedCloseClients(); UpdateNotifyBackEndClientCount(nowMs); int clientSocketCount = m_data.m_socketListener.GetClientSocketCount(); if (m_data.m_webSessionListener != null) { clientSocketCount += m_data.m_webSessionListener.GetClientSocketCount(); } ServerStat.Instance.SetValue("SocketSessionMapCount", clientSocketCount); } private void CheckTimeoutClient() { long now = m_app.GetTimeSecond(); // 3秒检查一次,10超时 if(now - m_data.m_lastCheckTimeoutTime < 3) { return; } m_data.m_lastCheckTimeoutTime = now; List infoList; lock (m_clientDictLocker) { infoList = m_data.m_waitServerAckDict.Values.ToList(); } foreach (var info in infoList) { if (now - info.ConnectedTime > 30) { TraceLog.Error("GateClientService.CheckTimeoutClient session {0} wait server ack connet timeout", info.SessionID); AddToNeedCloseClient(info.SessionID); } } //等待公钥校验 lock (m_clientDictLocker) { infoList = m_data.m_waitClientPublicKeyDict.Values.ToList(); } foreach (var info in infoList) { if (now - info.ConnectedTime > 30) { TraceLog.Error("GateClientService.CheckTimeoutClient session {0} wait client public key timeout", info.SessionID); AddToNeedCloseClient(info.SessionID); } } } private void CloseNeedCloseClients() { if (m_data.m_needCloseClients.Count == 0) { return; } List closeSessionID; lock (m_needCloseClientsLocker) { closeSessionID = m_data.m_needCloseClients.ToList(); m_data.m_needCloseClients.Clear(); } foreach (long sessionID in closeSessionID) { lock (m_clientDictLocker) { m_data.m_waitServerAckDict.Remove(sessionID); m_data.m_waitClientPublicKeyDict.Remove(sessionID); } GateClientInfo info = GetGateClientInfoThreadSafe(sessionID); if (info != null) { // 通知后端服务器客户端断线了 GateServerUtils.GetServerMsgTrans().NotifyServerClientDisconnected(info.SessionID, info.LinkServerID); if (info.Session is WebSession) { if (info.Session.WorkSocket != null) { m_data.m_webSessionListener.ForceCloseNetSession(info.Session); } } else { if (info.Session.WorkSocket != null) { m_data.m_socketListener.ForceCloseNetSession(info.Session); } } lock (m_clientDictLocker) { m_data.m_clientsDict.Remove(sessionID); } } } } public void OnServerAckConnected(uint remoteAppID, long sessionID) { GateClientInfo info; lock (m_clientDictLocker) { if (m_data.m_waitServerAckDict.TryGetValue(sessionID, out info)) { m_data.m_waitServerAckDict.Remove(sessionID); } } if (info == null) { TraceLog.Trace("GateClientService.OnServerAckConnected server ack session {0} conneted, but client not in waitlist", sessionID); } info = GetGateClientInfoThreadSafe(sessionID); if (info != null) { TraceLog.Trace("GateClientService.OnServerAckConnected server {0} ack session {1} conneted ,change state to normal" , ServerIDUtils.IDToString(remoteAppID), sessionID); info.LinkServerID = remoteAppID; info.State = GameClientState.Noraml; } else { TraceLog.Error("GateClientService.OnServerAckConnected server ack session {0} conneted, but client not in m_clientsDict, server login error!" , sessionID); } } //服务器主动断开连接 public void OnServerReqDisconnect(uint remoteAppID,long sessionID) { GateClientInfo info = GetGateClientInfoThreadSafe(sessionID); if (info != null) { TraceLog.Trace("GateClientService.OnServerReqDisconnect server req session {0} disconnect ,add to close list" , sessionID); info.State = GameClientState.Closed; AddToNeedCloseClient(sessionID); } else { TraceLog.Trace("GateClientService.OnServerReqDisconnect server req session {0} disconnect ,but client not in m_clientsDict" , sessionID); //不存在了,不回包算了 zouwei 20180604 //回个包比较好,兼容性更好,比如game运行的时候可以杀gate进程,还有切服兼容 20190214 GateServerUtils.GetServerMsgTrans().NotifyServerClientDisconnected(sessionID, remoteAppID); } } public void TransChannelMessageToClient(uint remoteAppID, long sessionID, MessageData channelMessage) { GateClientInfo info = GetGateClientInfoThreadSafe(sessionID); if (info == null) { TraceLog.Trace("GateClientService.TransChannelMessageToClient can not find session {0}, drop msg" , sessionID); //回个包比较好,兼容性更好,比如game运行的时候可以杀gate进程,还有切服兼容 20190214 GateServerUtils.GetServerMsgTrans().NotifyServerClientDisconnected(sessionID, remoteAppID); return; } if (info.State != GameClientState.Noraml) { TraceLog.Trace("GateClientService.TransChannelMessageToClient session {0} stat {1} need Noraml, drop msg" , sessionID, info.State); return; } int headLength = GateMsgHeaderPacker.GetLength(); MessageData message = new MessageData(); message.Header.Type = channelMessage.Header.Type; int iChannelDataLength = channelMessage.Header.Length - headLength; if (iChannelDataLength < 0) { TraceLog.Trace("GateClientService.TransChannelMessageToClient session {0} channelMessage length error" , sessionID); return; } //加个判断,大消息打个日志 if (iChannelDataLength > 60000) { TraceLog.Error("GateClientService.TransChannelMessageToClient session {0} channelMessage length {1} too long, msg type {2}" , sessionID, iChannelDataLength, message.Header.Type); } message.MallocData(iChannelDataLength); Buffer.BlockCopy(channelMessage.Buffer.Data, headLength, message.Buffer.Data, 0, message.Buffer.Length); // 消息压缩 if (ZipClientMsgSize > 0 && message.Buffer.Length > ZipClientMsgSize) { ZipMessageData(message, info); } // 消息加密, 空消息不加密 if (info.TeaKey != null && iChannelDataLength > 0) { SogFastXTEA.Encrypt(message.Buffer.Data, message.Buffer.Length, info.TeaKey); } message.Header.Length = message.Buffer.Length; message.Header.ObjectID = 0; //发给客户端的这个全部设置成空 info.SendSeq++; TraceLog.Trace("GateClientService.TransChannelMessageToClient session {0} MsgType {1} length {2}", sessionID, message.Header.Type, message.Header.Length); SendSessionMessage(info.Session, message); } public void ZipMessageData(MessageData message, GateClientInfo info) { byte[] zipData = ZipUtils.CompressBytes(message.Buffer.Data, message.Buffer.Length); if (zipData.Length < message.Buffer.Length) { TraceLog.Trace("GateClientService.ZipMessageData message {0} old {1} zip {2}" , message.Header.Type, message.Buffer.Length, zipData.Length); Buffer.BlockCopy(zipData, 0, message.Buffer.Data, 0, zipData.Length); message.Buffer.Length = zipData.Length; message.Header.isZip = true; } else { TraceLog.Error("GateClientService.ZipMessageData message {0} not zip, old {1} < zip {2}" , message.Header.Type, message.Buffer.Length, zipData.Length); } } public void TransChannelMessageToMultiClient(ref GateMsgMultiSessionHeader mutilsession, MessageData channelMessage) { //总消息长度 int headLength = GateMsgHeaderPacker.GetLength() + mutilsession.GetLength(); int iChannelDataLength = channelMessage.Header.Length - headLength; if (iChannelDataLength < 0) { TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans message {0},channelMessage length error " , channelMessage.Header.Type); return; } //加个判断,免得不知道错误 if (iChannelDataLength > 60000) { TraceLog.Error("GateClientService.TransChannelMessageToMultiClient trans message {0} ,channelMessage length {1} too long" , channelMessage.Header.Type,iChannelDataLength); return; } unsafe { for (int i = 0; i < mutilsession.Count; i++) { long sessionId = mutilsession.SessionIDs[i]; GateClientInfo info = GetGateClientInfoThreadSafe(sessionId); if (info == null) { TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans session {0} message ,but can not find session" , sessionId); continue; } if (info.State != GameClientState.Noraml) { TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans session {0} message ,but session stat is {1}" , sessionId, GameClientState.Noraml); continue; } info.SendSeq++; MessageData message = new MessageData(); message.Header.Type = channelMessage.Header.Type; message.Header.ObjectID = 0; //发给客户端的这个全部设置成空 message.MallocData(iChannelDataLength); Buffer.BlockCopy(channelMessage.Buffer.Data, headLength, message.Buffer.Data, 0, message.Buffer.Length); // 广播应用不多, 后续可以把消息压缩改成1次 if (ZipClientMsgSize > 0 && message.Buffer.Length > ZipClientMsgSize) { ZipMessageData(message, info); } //空消息不加密 if (info.TeaKey != null && iChannelDataLength > 0) { SogFastXTEA.Encrypt(message.Buffer.Data, message.Buffer.Length, info.TeaKey); } message.Header.Length = message.Buffer.Length; SendSessionMessage(info.Session, message); TraceLog.Trace("GateClientService.TransChannelMessageToMultiClient trans session {0} message ,MsgType {1} length {2}", sessionId, message.Header.Type, message.Header.Length); } } } private void AddToNeedCloseClient(long sessionID) { lock (m_needCloseClientsLocker) { if (m_data.m_needCloseClients.Contains(sessionID)) { return; } m_data.m_needCloseClients.Add(sessionID); } } private void OnRecvClientPublicKey(GateClientInfo info, long sessionID, MessageData message) { lock (m_clientDictLocker) { m_data.m_waitClientPublicKeyDict.Remove(sessionID); } if(message.Buffer.Length > 2) { int modLen = BitConverter.ToInt16(message.Buffer.Data, 0); int expLen = message.Buffer.Length - modLen - 2; if (modLen < 0 || expLen < 0) { TraceLog.Debug("GateClientService.OnRecvClientPublicKey session {0} length invalid" , sessionID); return; } byte[] mod = new byte[modLen]; byte[] exp = new byte[expLen]; Buffer.BlockCopy(message.Buffer.Data, 2, mod, 0, modLen); Buffer.BlockCopy(message.Buffer.Data, 2 + modLen, exp, 0, expLen); byte[] newTeaKey = TeaKeyGenerator.Instance.GenerateNew(); byte[] encrypteaKey = null; if (expLen == 4) { //自己特殊rsa算法 encrypteaKey = CryptoConvertUtils.EncryptWithPublicKeyWithChewKeongTANBigInteger(newTeaKey, mod, exp); TraceLog.Debug("GateClientService.OnRecvClientPublicKey EncryptWithPublicKeyWithChewKeongTANBigInteger session {0} keyLen {1}" , sessionID, encrypteaKey.Length); } else { TraceLog.Debug("GateClientService.OnRecvClientPublicKey EncryptWithPublicKey session {0}" , sessionID); TraceLog.Error("GateClientService.OnRecvClientPublicKey EncryptWithPublicKey session {0} no support" , sessionID); return; //通用rsa算法,和微软的实现一样 //encrypteaKey = CryptoConvertUtils.EncryptWithPublicKey(newTeaKey, mod, exp); } MessageData sessionKeyMessage = new MessageData(); sessionKeyMessage.Header.ObjectID = 0; sessionKeyMessage.Header.ServerID = 0; sessionKeyMessage.Header.Type = (int)SpecialMessageType.SessionKey; sessionKeyMessage.Header.Length = encrypteaKey.Length; //拷贝一份数据,目的是所有的MessageData的内存全都走cache,这样统一 sessionKeyMessage.MallocData(encrypteaKey.Length); Buffer.BlockCopy(encrypteaKey, 0, sessionKeyMessage.Buffer.Data, 0, encrypteaKey.Length); SendSessionMessage(info.Session, sessionKeyMessage); info.TeaKey = new SogFastXTEAKey(newTeaKey); } } private void SendSessionMessage(NetSession session, MessageData message) { if (session is WebSession) { m_data.m_webSessionListener.Send(session, message); } else { m_data.m_socketListener.Send(session, message); } } /// /// 通知后端服务器连接数量 /// private void UpdateNotifyBackEndClientCount(long nowMs) { //10秒一个包 if(nowMs - m_lastNotifyBackEndClientCountTimeMs < 10000) { return; } m_lastNotifyBackEndClientCountTimeMs = nowMs; GateServerUtils.GetServerMsgTrans().NotifyServerClientCount(GetClientCount()); } } }