如何在 C# 中获取服务器和客户端之间的延迟?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/770978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I obtain the latency between server and client in C#?
提问by DfKimera
I'm working on a C# Server application for a game engine I'm writing in ActionScript 3. I'm using an authoritative server model as to prevent cheating and ensure fair game. So far, everything works well:
我正在为我在 ActionScript 3 中编写的游戏引擎开发 C# 服务器应用程序。我使用权威服务器模型来防止作弊并确保公平游戏。到目前为止,一切正常:
When the client begins moving, it tells the server and starts rendering locally; the server, then, tells everyone else that client X has began moving, among with details so they can also begin rendering. When the client stops moving, it tells the server, which performs calculations based on the time the client began moving and the client render tick delay and replies to everyone, so they can update with the correct values.
当客户端开始移动时,它会通知服务器并开始本地渲染;然后,服务器告诉其他人客户端 X 已经开始移动,其中包含细节,以便他们也可以开始渲染。当客户端停止移动时,它告诉服务器,服务器根据客户端开始移动的时间和客户端渲染滴答延迟执行计算并回复每个人,以便他们可以使用正确的值进行更新。
The thing is, when I use the default 20ms tick delay on server calculations, when the client moves for a rather long distance, there's a noticeable tilt forward when it stops. If I increase slightly the delay to 22ms, on my local network everything runs very smoothly, but in other locations, the tilt is still there. After experimenting a little, I noticed that the extra delay needed is pretty much tied to the latency between client and server. I even boiled it down to a formula that would work quite nicely: delay = 20 + (latency / 10).
问题是,当我在服务器计算中使用默认的 20ms 滴答延迟时,当客户端移动相当长的距离时,当它停止时会明显向前倾斜。如果我将延迟稍微增加到 22 毫秒,在我的本地网络上一切运行都非常顺利,但在其他位置,倾斜仍然存在。经过一些实验,我注意到所需的额外延迟与客户端和服务器之间的延迟非常相关。我什至把它归结为一个非常有效的公式:延迟 = 20 +(延迟 / 10)。
So, how would I proceed to obtain the latency between a certain client and the server (I'm using asynchronous sockets). The CPU effort can't be too much, as to not have the server run slowly. Also, is this really the best way, or is there a more efficient/easier way to do this?
那么,我将如何继续获得某个客户端和服务器之间的延迟(我使用的是异步套接字)。CPU 工作量不能太多,以免服务器运行缓慢。另外,这真的是最好的方法,还是有更有效/更简单的方法来做到这一点?
采纳答案by Kylotan
Sorry that this isn't directly answering your question, but generally speaking you shouldn't rely too heavily on measuring latency because it can be quite variable. Not only that, you don't know if the ping time you measure is even symmetrical, which is important. There's no point applying 10ms of latency correction if it turns out that the ping time of 20ms is actually 19ms from server to client and 1ms from client to server. And latency in application terms is not the same as in networking terms - you may be able to ping a certain machine and get a response in 20ms but if you're contacting a server on that machine that only processes network input 50 times a second then your responses will be delayed by an extra 0 to 20ms, and this will vary rather unpredictably.
抱歉,这并不能直接回答您的问题,但一般而言,您不应过分依赖测量延迟,因为它可能变化很大。不仅如此,你不知道你测得的ping时间是否是对称的,这很重要。如果结果证明 20 毫秒的 ping 时间实际上是从服务器到客户端的 19 毫秒和从客户端到服务器的 1 毫秒,那么应用 10 毫秒的延迟校正是没有意义的。应用程序方面的延迟与网络方面的延迟不同 - 您可能能够 ping 某台机器并在 20 毫秒内得到响应,但是如果您正在联系该机器上的服务器,该服务器每秒只处理 50 次网络输入,那么您的响应将额外延迟 0 到 20 毫秒,并且这会发生相当不可预测的变化。
That's not to say latency measurement it doesn't have a place in smoothing predictions out, but it's not going to solve your problem, just clean it up a bit.
这并不是说延迟测量在平滑预测方面没有作用,但它不会解决您的问题,只需稍微清理一下即可。
On the face of it, the problem here seems to be that that you're sent information in the first message which you use to extrapolate data from until the last message is received. If all else stays constant then the movement vector given in the first message multiplied by the time between the messages will give the server the correct end position that the client was in at roughly now-(latency/2). But if the latency changes at all, the time between the messages will grow or shrink. The client may know he's moved 10 units, but the server simulated him moving 9 or 11 units before being told to snap him back to 10 units.
从表面上看,这里的问题似乎是在第一条消息中向您发送信息,用于推断数据,直到收到最后一条消息。如果其他一切都保持不变,那么第一条消息中给出的移动向量乘以消息之间的时间将为服务器提供客户端大致现在所处的正确结束位置(延迟/2)。但如果延迟发生了变化,消息之间的时间就会增加或缩短。客户端可能知道他移动了 10 个单位,但服务器模拟他移动了 9 或 11 个单位,然后被告知将他弹回 10 个单位。
The general solution to this is to not assume that latency will stay constant but to send periodic position updates, which allow the server to verify and correct the client's position. With just 2 messages as you have now, all the error is found and corrected after the 2nd message. With more messages, the error is spread over many more sample points allowing for smoother and less visible correction.
对此的一般解决方案是不假设延迟将保持不变,而是发送定期位置更新,这允许服务器验证和纠正客户端的位置。现在只有 2 条消息,在第 2 条消息后发现并纠正了所有错误。有了更多的消息,误差就会分布在更多的样本点上,从而实现更平滑、更不明显的校正。
It can never be perfect though: all it takes is a lag spike in the last millisecond of movement and the server's representation will overshoot. You can't get around that if you're predicting future movement based on past events, as there's no real alternative to choosing either correct-but-late or incorrect-but-timely since information takes time to travel. (Blame Einstein.)
然而,它永远不可能是完美的:它所需要的只是运动的最后一毫秒的滞后峰值,并且服务器的表示将过冲。如果您根据过去的事件预测未来的运动,则无法解决这个问题,因为除了选择正确但迟到或不正确但及时之外别无选择,因为信息需要时间来传递。(怪爱因斯坦。)
回答by Adam Robinson
Have a "ping" command, where you send a message from the server to the client, then time how long it takes to get a response. Barring CPU overload scenarios, it should be pretty reliable. To get the one-way trip time, just divide the time by 2.
有一个“ping”命令,您可以在其中从服务器向客户端发送消息,然后计算获得响应所需的时间。除非 CPU 过载情况,否则它应该非常可靠。要获得单程旅行时间,只需将时间除以 2。
回答by leen
回答by Sim
One thing to keep in mind when using ICMPbased pingsis that networking equipment will often give ICMP traffic lower priority than normalpackets, especially when the packets cross network boundaries such as WAN links. This can lead to pings being dropped or showing higher latency than traffic is actually experiencing and lends itself to being an indicator of problems rather than a measurement tool.
使用基于ICMP的ping时要记住的一件事是,网络设备通常会给 ICMP 流量比普通数据包更低的优先级,尤其是当数据包跨越网络边界(如 WAN 链接)时。这可能导致 ping 被丢弃或显示比流量实际经历更高的延迟,并有助于成为问题的指示器而不是测量工具。
The increasing use of Quality of Service(QoS) in networks only exacerbates this and as a consequence though ping still remains a useful tool, it needs to be understood that it may not be a true reflection of the network latency for non-ICMP based realtraffic.
在网络中越来越多地使用服务质量(QoS) 只会加剧这种情况,因此尽管 ping 仍然是一个有用的工具,但需要理解的是,对于非基于 ICMP 的真实网络,它可能不是网络延迟的真实反映。交通。
There is a good post at the Itrinegy blog How do you measure Latency (RTT) in a network these days?about this.
Itrinegy 博客上有一篇很好的帖子,这些天你如何测量网络中的延迟 (RTT)?对这个。
回答by Stephen Kennedy
We can measure the round-triptimeusing the Ping
class of the .NET Framework.
我们可以使用.NET Framework的类来测量往返时间Ping
。
Instantiate a Ping
and subscribe to the PingCompleted
event:
实例化 aPing
并订阅PingCompleted
事件:
Ping pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
Add code to configure and action the ping.
添加代码以配置和操作 ping。
Our PingCompleted
event handler (PingCompletedEventHandler
) has a PingCompletedEventArgs
argument. The PingCompletedEventArgs.Reply
gets us a PingReply
object. PingReply.RoundtripTime
returns the round trip time (the "number of milliseconds taken to send an Internet Control Message Protocol (ICMP) echo request and receive the corresponding ICMP echo reply message"):
我们的PingCompleted
事件处理程序 ( PingCompletedEventHandler
) 有一个PingCompletedEventArgs
参数。在PingCompletedEventArgs.Reply
得到我们PingReply
的对象。PingReply.RoundtripTime
返回往返时间(“发送 Internet 控制消息协议 (ICMP) 回显请求并接收相应的 ICMP 回显回复消息所花费的毫秒数”):
public static void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
...
Console.WriteLine($"Roundtrip Time: {e.Reply.RoundtripTime}");
...
}
Code-dump of a full working example, based on MSDN's example. I have modified it to write the RTT to the console:
基于MSDN 示例的完整工作示例的代码转储。我已经修改它以将 RTT 写入控制台:
public static void Main(string[] args)
{
string who = "www.google.com";
AutoResetEvent waiter = new AutoResetEvent(false);
Ping pingSender = new Ping();
// When the PingCompleted event is raised,
// the PingCompletedCallback method is called.
pingSender.PingCompleted += PingCompletedCallback;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
// Wait 12 seconds for a reply.
int timeout = 12000;
// Set options for transmission:
// The data can go through 64 gateways or routers
// before it is destroyed, and the data packet
// cannot be fragmented.
PingOptions options = new PingOptions(64, true);
Console.WriteLine("Time to live: {0}", options.Ttl);
Console.WriteLine("Don't fragment: {0}", options.DontFragment);
// Send the ping asynchronously.
// Use the waiter as the user token.
// When the callback completes, it can wake up this thread.
pingSender.SendAsync(who, timeout, buffer, options, waiter);
// Prevent this example application from ending.
// A real application should do something useful
// when possible.
waiter.WaitOne();
Console.WriteLine("Ping example completed.");
}
public static void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
// If the operation was canceled, display a message to the user.
if (e.Cancelled)
{
Console.WriteLine("Ping canceled.");
// Let the main thread resume.
// UserToken is the AutoResetEvent object that the main thread
// is waiting for.
((AutoResetEvent)e.UserState).Set();
}
// If an error occurred, display the exception to the user.
if (e.Error != null)
{
Console.WriteLine("Ping failed:");
Console.WriteLine(e.Error.ToString());
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
Console.WriteLine($"Roundtrip Time: {e.Reply.RoundtripTime}");
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
You might want to perform several pings and then calculate an average, depending on your requirements of course.
您可能想要执行几次 ping,然后计算平均值,这当然取决于您的要求。