【问题标题】:Ensure queued messages are sent in correct order确保以正确的顺序发送排队的消息
【发布时间】:2018-07-30 16:15:25
【问题描述】:

我有一个客户端-服务器架构,使用 TCP 进行通信。客户端以 1msg/70ms 的速率向客户端发送消息。服务器必须模拟网络延迟,因此在服务器接收端,我执行以下操作:

//Event handler for new messages
private void DataReceived(object sender, DataReceivedEventArgs args)
{
    //Add raw data to a queue for processing at a later time
    TemporaryRawMessages.Enqueue(args.Bytes);
    args.Recycle();
}

//Function running on thread; processes newly arrived raw messages
//new messages are removed from the queue, given their own thread and processed independently. 
void ProcessMessagesIn()
{
    while (true)
    {

        if (TemporaryRawMessages.Count > 0)
        {
            var raw = TemporaryRawMessages.Dequeue();
            var t = new Thread(() => {
                Thread.Sleep(LatencyUp);
                var message = (ClientToServerMessage)Utils.Deserialize(raw_message);
                Messages_In.Enqueue(message);
            });
            t.Start();
        }

    }
}

//Create & start a thread to processes incoming messages
var processMessagesIn = new Thread(ProcessMessagesIn);
processMessagesIn.Start();

注意LatencyUp 变量。我希望来自客户端的消息延迟 b x 毫秒,但平均间隔为 1msg/70ms。换句话说,所有消息相隔 70 毫秒,但偏移 LatencyUp

我还为从服务器到客户端的消息添加了延迟,以表示网络停机延迟:

Task.Factory.StartNew(() => { SendLoop(); });

void SendToClient(ServerToClientMessage message)
{
    Messages_Out.Enqueue(message);
}

void SendLoop()
{
    while (true)
    {
        if(Messages_Out.Count > 0)
        {
            ServerToClientMessage message_out = null;
            Messages_Out.TryDequeue(out message_out);

            if(message_out != null)
            {
                Thread myNewThread = new Thread(() =>
                {
                    Thread.Sleep(LatencyDown);
                    if (ClientConnection != null && ClientConnection.State == ConnectionState.Connected)
                    {
                        var serialized = Utils.Serialize(message);
                        ClientConnection.SendBytes(serialized, SendOption.Reliable);
                    }
                });

                myNewThread.Start();
            }
        }
    }
}

我也试过这样发送,没有从服务器到客户端的消息队列:

void SendToClient(ServerToClientMessage message)
{
    Thread myNewThread = new Thread(() =>
    {
        Thread.Sleep(LatencyDown);
        Send(message);
    });

    myNewThread.Start();
}

问题

有时从服务器到客户端的消息会混淆...例如,消息 2 可能在消息 1 之前发送。

我不完全确定为什么。消息以正确的顺序放入队列(我已经检查过了)。在添加到队列和出队 + 发送之间的某个地方,出了点问题。

我唯一能想到的是一个线程在另一个线程之前完成,但我想不出这是怎么发生的。

我可以做些什么来确保消息按照发送的顺序(客户端到服务器)被接收并以正确的顺序从服务器发送到客户端?

性能(在处理速度方面)很重要,因此对于该主题的任何改进/建议也将不胜感激。

【问题讨论】:

  • 您正在为每条消息启动一个线程,所以是的,这可能会引入延迟本身,从而导致一个线程在较早开始的线程之前完成。为什么每条消息都使用一个线程,而不是单个消息发送线程?
  • 我不知道您是如何从 “我需要一个偏移量”“我将在每条消息中使用一个线程”,但是你需要修改那个设计。
  • 这是学校作业吗?您是否正确地完成了作业。我不确定如何使用 TCP 连接来模拟 TCP 延迟。我认为您将使用 FIFO 来模拟 TCP 连接。您无法控制连接或流的时间,因为 Windows 使用流类中的计时器来移动数据(Timer Tick Server)。所以数据不会均匀分布。
  • 如果需要按顺序发送消息,则必须排队。没有什么能保证数百个新创​​建的线程将按照它们的创建顺序执行。此外,while (true) 仅适用于在寒冷的冬夜温暖您的房间,并缩短 CPU 的使用寿命。
  • new Thread(() => fifo.Enqueue(x)); 无法确保正确的顺序。线程不是按顺序执行的,因此它们在后台执行的任何操作都不是按顺序执行的。另外请记住,每次创建新线程时,都会产生大量 CPU 开销(用于创建线程,而不是使用 ThreadPool)和内存开销(默认为每个新创建的线程分配 1MB 堆栈)。

标签: c# multithreading tcp


【解决方案1】:

您不能使用多个线程按顺序分派事件。如果你想为你的数据生产者提供一个异步消费者,你只需要一个线程。

创建生产者-消费者队列的最简单方法是使用BlockingCollection<T>

var blockingCollection = new BlockingCollection<int>();

// this is a single, one and only producer thread
Task.Run(() =>
{
    var number = 0;
    while (true)
    {
        number++;
        Console.WriteLine("tx --> " + number);
        blockingCollection.Add(number);
        Task.Delay(1000).Wait();
    }
});

// single, one and only consumer thread
foreach (var item in blockingCollection.GetConsumingEnumerable())
{
    Task.Delay(200).Wait();
    Console.WriteLine("    " + item + " --> rx");
}

【讨论】:

  • 谢谢,我试试看。
  • 啊,但这行不通……它只会在 foreach 中的消息之间延迟 200 毫秒,并在 1 秒内添加另一条消息,因此每条消息将间隔 1.2 秒的延迟。
  • @pookie:如果我没记错的话,两条消息应该用 1 分隔。 rx 部分只是偏移了 200ms。但无论如何这是一般的想法,你只需要两个不同的线程(生产者+消费者)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-09
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多