【发布时间】: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