public AsyncSocket Connect(GlobalClient client) { lock (this) { // 这个能放到(lock(this)外吗?严格点,放这里更安全。 // TODO IsCompletedSuccessfully net471之类的没有这个方法,先不管。net471之类的unity要用。 if (null != Logined && Logined.Task.IsCompletedSuccessfully) { return(Logined.Task.Result); } if (global::Zeze.Util.Time.NowUnixMillis - LastErrorTime < ForbitPeriod) { throw new AbortException("GloalAgent.Connect: In Forbit Login Period"); } if (null == Socket) { Socket = client.NewClientSocket(Host, Port, this); // 每次新建连接创建future,没并发问题吧,还没仔细考虑。 Logined = new TaskCompletionSource <AsyncSocket>(); } } // 重新设置一个总超时。整个登录流程有ConnectTimeout,LoginTimeout。 // 要注意,这个超时发生时,登录流程可能还在进行中。 // 这里先不清理,下一次进来再次等待(需要确认这样可行)。 if (false == Logined.Task.Wait(5000)) { lock (this) { // 并发的等待,简单用个规则:在间隔期内不再设置。 long now = global::Zeze.Util.Time.NowUnixMillis; if (now - LastErrorTime > ForbitPeriod) { LastErrorTime = now; } } throw new AbortException("GloalAgent.Connect: Login Timeout"); } return(Socket); }
public void OnSocketClose(GlobalClient client, Exception ex) { lock (this) { if (null == Socket) { // active close return; } Socket = null; } if (Logined.Task.IsCompletedSuccessfully) { foreach (var database in client.Zeze.Databases.Values) { foreach (var table in database.Tables) { table.ReduceInvalidAllLocalOnly(GlobalCacheManagerHashIndex); } } client.Zeze.CheckpointRun(); } Logined.TrySetException(ex); // 连接关闭,这个继续保持。仅在Connect里面需要时创建。 }
public void Start(string hostNameOrAddress, int port) { lock (this) { if (null != Client) { return; } Client = new GlobalClient(this, Zeze); // Zeze-App 自动启用持久化的全局唯一的Rpc.SessionId生成器。 Client.SessionIdGenerator = Zeze.TableSys.AutoKeys.GetAutoKey(Client.Name).Next; Client.AddFactoryHandle(new GlobalCacheManager.Reduce().TypeId, new Service.ProtocolFactoryHandle() { Factory = () => new GlobalCacheManager.Reduce(), Handle = ProcessReduceRequest, NoProcedure = true }); Client.AddFactoryHandle(new GlobalCacheManager.Acquire().TypeId, new Service.ProtocolFactoryHandle() { Factory = () => new GlobalCacheManager.Acquire(), NoProcedure = true // 同步方式调用,不需要设置Handle: Response Timeout }); Client.AddFactoryHandle(new GlobalCacheManager.Login().TypeId, new Service.ProtocolFactoryHandle() { Factory = () => new GlobalCacheManager.Login(), NoProcedure = true }); Client.AddFactoryHandle(new GlobalCacheManager.ReLogin().TypeId, new Service.ProtocolFactoryHandle() { Factory = () => new GlobalCacheManager.ReLogin(), NoProcedure = true }); Client.AddFactoryHandle(new GlobalCacheManager.NormalClose().TypeId, new Service.ProtocolFactoryHandle() { Factory = () => new GlobalCacheManager.NormalClose(), NoProcedure = true }); var globals = hostNameOrAddress.Split(';'); Agents = new Agent[globals.Length]; for (int i = 0; i < globals.Length; ++i) { var hp = globals[i].Split(':'); if (hp.Length > 1) { Agents[i] = new Agent(hp[0], int.Parse(hp[1]), i); } else { Agents[i] = new Agent(hp[0], port, i); } } foreach (var agent in Agents) { try { agent.Connect(Client); } catch (Exception ex) { // 允许部分GlobalCacheManager连接错误时,继续启动程序,虽然后续相关事务都会失败。 logger.Error(ex, "GlobalAgent.Connect"); } } } }