我有一个客户端 - 服务器架构,使用TCP进行通信。客户端以1msg / 70ms的速率向客户端发送消息。服务器必须模拟网络延迟,因此在服务器接收方面,我会执行以下操作:
A
注意//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();
变量。我希望来自客户端的消息延迟b x毫秒,但均匀间隔为1msg / 70ms。换句话说,所有消息相隔70毫秒,但偏移LatencyUp
。
我还将消息从服务器发送到客户端,以表示网络停机延迟:
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();
}
}
}
}
问题
有时从服务器到客户端的消息混淆了......例如,消息2可能会在消息1之前发送。
我不完全确定原因。消息以正确的顺序放入队列(我已经检查了这个)。在添加到队列和出队+发送之间的某处,出现了问题。
我唯一能想到的是一个线程在另一个线程之前完成,但我无法想象这会如何发生。
我可以做些什么来确保按照发送的顺序(客户端到服务器)接收邮件,并以正确的顺序从服务器发送到客户端?
性能(在处理速度方面)非常重要,因此有关该主题的任何改进/建议也将受到赞赏。
答案 0 :(得分:0)
您不能使用多个线程按顺序分派事件。如果您想为数据生成器创建异步使用者,那么您只需要一个线程。
创建生产者 - 消费者队列的最简单方法是使用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");
}