Server 桌面应用程序的客户端/服务器状态同步

Server 桌面应用程序的客户端/服务器状态同步,server,synchronization,client,desktop-application,messaging,Server,Synchronization,Client,Desktop Application,Messaging,我正在开发一个桌面应用程序,它需要在多个客户端之间进行同步。基本上,一组人(比如说2到10人)都运行相同的应用程序。其中一个托管服务器,另一个客户端连接到该服务器。托管服务器的客户端也连接到自己的服务器 应用程序应在所有客户端之间保持同步,这意味着所有客户端在应用程序中看到相同的数据。具体而言,我可以用两种不同的形式定义所讨论的数据: 具有特定值的简单属性(此值必须保持同步) 属性列表(列表中的项及其值必须保持同步) (1)的简单示例可能是:客户端当前选择了列表中的哪个项目,以及客户端鼠标指针在

我正在开发一个桌面应用程序,它需要在多个客户端之间进行同步。基本上,一组人(比如说2到10人)都运行相同的应用程序。其中一个托管服务器,另一个客户端连接到该服务器。托管服务器的客户端也连接到自己的服务器

应用程序应在所有客户端之间保持同步,这意味着所有客户端在应用程序中看到相同的数据。具体而言,我可以用两种不同的形式定义所讨论的数据:

  • 具有特定值的简单属性(此值必须保持同步)
  • 属性列表(列表中的项及其值必须保持同步)
  • (1)的简单示例可能是:客户端当前选择了列表中的哪个项目,以及客户端鼠标指针在应用程序窗口中的当前位置。这些特性不断变化,但这些特性的数量是恒定的,不会增长(例如,在设计期间定义)

    (2)的示例可以是聊天信息列表。这些列表将在运行时增长,无法预测将有多少项

    下面是C#中有关状态、客户端和聊天消息的示例代码:

    public class State
    {
        // A single value shared between all clients
        public int SimpleInteger {get;set;}
    
        // List of connected clients and their individual states
        public List<Client> Clients {get;set;}
    
        // List of chat messages
        public List<ChatMessage> Messages {get;set;}
    }
    
    public class Client 
    {
        public string ClientId {get;set;}
        public string Username {get;set;}
    
        public ClientState ClientState {get;set;}
    }
    
    public class ClientState 
    {
        public string ClientId {get;set;}
        public int SelectedIndex {get;set;}
        public int MouseX {get;set;}
        public int MouseY {get;set;}
    }
    
    public class ChatMessage 
    {
        public string ClientId {get;set;}
        public string Message {get;set;}
    }
    
    公共类状态
    {
    //所有客户端之间共享的单个值
    公共int-SimpleInteger{get;set;}
    //已连接客户端及其各个状态的列表
    公共列表客户端{get;set;}
    //聊天信息列表
    公共列表消息{get;set;}
    }
    公共类客户端
    {
    公共字符串ClientId{get;set;}
    公共字符串用户名{get;set;}
    公共客户端状态客户端状态{get;set;}
    }
    公共类客户端状态
    {
    公共字符串ClientId{get;set;}
    public int SelectedIndex{get;set;}
    公共int MouseX{get;set;}
    公共int鼠标{get;set;}
    }
    公共类聊天信息
    {
    公共字符串ClientId{get;set;}
    公共字符串消息{get;set;}
    }
    
    我已经断断续续地做了很长一段时间了,但是不管我想出了什么样的状态同步,它都没有很好地工作

    当我搜索解决方案时,我只找到游戏的解决方案,但这些解决方案没有多大帮助,因为我的要求不同:

    • 我无法处理“删除的更新”,我无法预测(插入或推断)其他客户正在做什么。每个客户端都需要接收每个更新以保持同步
    • 另一方面,我不在乎滞后(在合理范围内)。如果我看到其他客户端的更新延迟大约一秒,这是可以的
    • 当新客户端连接(或重新连接)时,必须传输大部分状态(例如:示例2中的聊天消息列表)。每个客户端都需要知道聊天的整个历史记录,因此在客户端连接时必须下载该记录
    我目前的解决方案可以总结如下:

    • 服务器跟踪状态,例如真相来源
    • 状态包含需要同步的属性
    • 该状态还包含已连接用户(及其用户名等)的列表
    • 客户还各自保留一份州的本地副本,他们可以立即采取行动。例如,它们不断更新其本地状态中的鼠标位置
    • 每当客户端更新其本地状态时,都会将此更新发送到服务器。
      • 这里潜在的例外是变化太快的东西,比如鼠标位置,我只会定期发送
    • 服务器还更新公共“真相来源”状态
    • 最后,服务器用新的更新状态更新所有其他客户端
    最后两步是我挣扎的地方。我可以想出两种方法来同步状态,一种简单但可能效率不高,另一种高效但容易出错

  • 服务器只是将整个状态发送给所有客户端。
    • 一旦服务器从客户端接收到更新,更新就会应用到状态,并广播新状态。其他每个客户端都会替换其本地状态
    • 我觉得这可能会起作用,但由于“列表”项(例如聊天信息),状态可能会迅速扩大。在我以前的尝试中,这很快成为一个问题,将状态发送回变得太慢
  • 服务器将收到的相同更新重新发送给所有其他客户端。
    • 然后,每个客户端仅将新更新应用于其本地状态,以便与服务器同步
    • 这可能效率更高,只有在客户端连接时才需要发送整个状态
    • 然而,在过去,我经常遇到客户机不再同步的去同步问题。我真的不知道是什么导致了它,可能是消息之间的冲突(例如,服务器告诉客户机更新状态中的值,但客户机只是更新了其本地值,哪个值具有优先级?)。在这种情况发生之后,一切都变得完全错误,因为更新现在应用于两个不同的状态,并产生不同的结果
  • 我正在寻找一些关于如何实现这一目标的一般概念的指导。我正在使用几个消息传递库来实现客户端和服务器之间的实际通信,我认为这一部分不是问题。例如,我可以确保在这些库中收到每一条消息(尽管我不确定订单是否得到保证)。正如我之前所说的,延迟不是问题,但我必须保证服务器和其他客户机都能接收到每个状态更新


    任何帮助都会很好!谢谢。

    这是一个复杂的问题,正如您所理解的,有许多活动部件。在我研究这个问题的过程中,我读到了一些关于李的问题的评论
    ​using System.Net.Sockets;
    using System.Net;
    using System;
    
    class Server {
        public static void Main() {
            TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 80);
    
            server.Start();
            Console.WriteLine("Server has started on 127.0.0.1:80.{0}Waiting for a connection...", Environment.NewLine);
    
            TcpClient client = server.AcceptTcpClient();
    
            Console.WriteLine("A client connected.");
        }
    }