帧同步 客户端同步 或 服务端同步 总结
客户端同步 方式是,客户端之间发送数据,获得数据后,合并到最近的一帧 来处理。服务器心跳继续保持
比如 ab之间 同步,服务器心跳 0.5秒一次,那么 一次比作 一帧。 a发b的时候,正好是 30帧时候,那么a以31帧的数据方式 给a b同时 接收。返回后 等待 心跳是 31的时候,再处理 之前 收的数据。
这样的好处就是,服务器压力小,服务器只要 负责心跳 以及 客户端 相互发送就可,不需要 任何记录操作。
但缺点很明显,发送量太大,ab之间发送,就是2次 给 客户端发,如果是 群体几十号玩家相互发,那一个玩家发一条 ,服务器就要发好几十条,最后变成n*n
所以,我改进了方法,采取 服务器同步法,同样 服务器心跳不变,时时刻刻告诉客户端 目前 是 第几帧。
客户端之间 相互发送,服务器 记录 ,在心跳当中 发射。
比如 ab 之间 互发消息。服务器记录的是 a 发的消息 和 在第几帧发的,当然因为延迟,我们肯定是 要再多加1帧,告知 是下一帧 转发客户端。那么心跳在 下一帧的时候,就发现有 一条记录,要求 ab都要收到 一条记录,然后 心跳就 不仅仅是发帧,还包含了 相关数据。
这样的好处就是,服务器 发送量 不会因为 并发大而 增加,发送量是 固定的。
坏处也有,就是 心跳每次都会检索一次每个 客户端 当前帧有没有数据要 发送。
相互发送服务器 片段代码,这里只负责存数据,不用来发送
//同时通知双方 static void OnSendDouble(string Type, string Playid, string Otherid, NetIncomingMessage msg) { //这个区块有存在 JsonDatas message = new JsonDatas(); message.jsons["type"] = Type; message.jsons["Frame"] = Frame + 1; message.jsons["playid"] = Playid; string json = JsonConvert.SerializeObject(message); //如果 这个帧 已经发射一次以上了 if (ServerModel.getInstance().OnSendeMessageDictionary.ContainsKey(Playid + "," + (Frame + 1))) { //Console.WriteLine(" 已经多次 " + Playid + "," + (Frame + 1)); ServerModel.getInstance().OnSendeMessageDictionary[Playid + "," + (Frame + 1)].Add(json); } else { // Console.WriteLine("第一次 " + Playid + "," + (Frame + 1)); List<string> jsonlist = new List<string>(); jsonlist.Add(json); ServerModel.getInstance().OnSendeMessageDictionary.Add(Playid + "," + (Frame + 1), jsonlist); } //如果 这个帧 已经发射一次以上了 if (ServerModel.getInstance().OnSendeMessageDictionary.ContainsKey(Otherid + "," + (Frame + 1))) { // Console.WriteLine(" 已经多次 " + Otherid + "," + (Frame + 1)); ServerModel.getInstance().OnSendeMessageDictionary[Otherid + "," + (Frame + 1)].Add(json); } else { // Console.WriteLine("第一次 " + Otherid + "," + (Frame + 1)); List<string> jsonlist = new List<string>(); jsonlist.Add(json); ServerModel.getInstance().OnSendeMessageDictionary.Add(Otherid + "," + (Frame + 1), jsonlist); } }
public static void Confrontation() { while (true) { Thread.Sleep(500); // Output("目前" + Frame); List<NetConnection> all = s_server.Connections; // get copy // all.Remove(msg.SenderConnection); if (all.Count > 0) { foreach (NetConnection NT in all) { NetOutgoingMessage om = s_server.CreateMessage(); JsonDatas message = new JsonDatas(); message.jsons["type"] = "7"; message.jsons["Frame"] = Frame; message.jsons["TF"] = 0; string id = ServerModel.getInstance().TSenderConnectionlDictionary[NT]; //如果 这个帧 有过发射 if (ServerModel.getInstance().OnSendeMessageDictionary.ContainsKey(id + "," + Frame)) { message.jsons["TF"] = 1; message.jsons["msg"] = JsonConvert.SerializeObject(ServerModel.getInstance().OnSendeMessageDictionary[id + "," + Frame]); string json = JsonConvert.SerializeObject(message); om.Write(json); s_server.SendMessage(om, NT, NetDeliveryMethod.ReliableOrdered, 0); ServerModel.getInstance().OnSendeMessageDictionary.Remove(id + "," + Frame); } else { string json = JsonConvert.SerializeObject(message); om.Write(json); s_server.SendMessage(om, NT, NetDeliveryMethod.ReliableOrdered, 0); } } } Frame++; } }
上面这个是心跳的片段代码
数据是 list方式,因为 可能一帧 会多次操作。key 是 id+帧 用完删