1

我正在使用 C# 和 XNA 开发一个小型在线多人乒乓球游戏。

我使用套接字在我的个人 LAN 上的两台计算机之间传输数据。它工作正常。

问题在于速度:传输速度很慢。

当我 ping 第二台计算机时,它显示 2 毫秒的延迟。我在我的代码中设置了一个小计时器,它显示大约 200 毫秒的延迟。即使服务器和客户端在同一台计算机上(使用 127.0.0.1),延迟仍然在 15 毫秒左右。我认为这很慢。

这是我的代码的一些片段:

server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, port));
server.Listen(1);
// Begin Accept
server.BeginAccept(new AsyncCallback(ClientAccepted), null);

在 ClientAccepted 中,我设置了一个 NetworkStream、一个 StreamReader 和一个 StreamWriter。当我想更新玩家的位置时,这就是我发送消息的方式:

string message = "P" + "\n" + player.Position + "\n";
byte[] data = Encoding.ASCII.GetBytes(message);
ns.BeginWrite(data, 0, data.Length, new AsyncCallback(EndUpdate), null);

EndUpdate 唯一要做的就是调用 EndWrite。这就是我接收数据的方式:

message = sr.ReadLine();

它不会阻止我的游戏,因为它在第二个线程上。

这些是我尝试过的东西: - 使用 IP 而不是 TCP - 使用二进制消息而不是文本 - 使用 IPv6 而不是 IPv4 没有任何帮助。

关于如何改善延迟的任何想法?

谢谢

4

4 回答 4

9

您看到的延迟很可能是由于Nagle 的算法,该算法用于在使用 TCP 发送大量小数据包时提高效率。本质上,TCP 堆栈将小数据包收集在一起,并在传输之前将它们合并成一个更大的数据包。这显然意味着在发送输出缓冲区中等待的内容之前延迟一小段时间 - 最多 200 毫秒 - 以查看是否发送了更多数据。

因此,尝试通过在套接字上将 NoDelay属性设置为 true 来关闭 Nagle 。

但是,请注意,如果您对套接字进行大量小型写入,则可能会因为 TCP 标头开销和每个数据包的处理而降低性能。在这种情况下,如果可能的话,您会想尝试将您的写入分批收集。

于 2009-01-08T01:04:25.927 回答
2

大多数网络游戏不使用 TCP 而是使用 UDP 进行通信。这样做的问题是数据很容易被丢弃,这是你必须考虑的事情。

使用 TCP,主机/服务器之间有许多交互来保证数据以有序的方式(使用 UDP 时您必须考虑的另一件事,即数据没有排序的事实)。

最重要的是,您代码中的计时器必须等到字节从非托管套接字层通过非托管代码等冒泡,等等。那里会有一些您无法克服的开销(非托管到托管的过渡)。

于 2009-01-08T00:54:29.330 回答
2

还有其他几个元问题需要考虑:

  1. 计时器精度:许多系统计时器仅每 15 毫秒左右更新一次。我不记得确切的值,但是如果您的时间总是大约 15 毫秒的倍数,请怀疑您的计时器精度不高。这“可能”不是您的问题,但请记住。

  2. 如果您在同一台计算机上进行测试,并且只运行单核机器,则线程/进程切换频率将支配您的 ping 时间。没什么可做的,只是尝试添加 Sleep(0) 调用以在发送数据后允许线程/进程交换。

  3. TCP/IP 传输设置。正如前面在 SocketOptionName.NoDelay 中提到的。同样如前所述,如果您不断更新状态,请考虑使用 UDP。不能保证顺序,但是对于易失性数据,丢失数据包是可以接受的,因为无论如何状态都会很快被覆盖。为避免使用过时的数据包,请向数据包添加一个递增值,并且永远不要使用标记早于当前状态的数据包。tcp 和 udp 之间的差异不应占 200 ms,但其他因素的组合可以。

  4. 轮询与选择。如果您正在轮询接收到的数据,那么轮询频率自然会干扰接收速率。我在一个专门的网络线程中使用 Socket.Select 来等待传入的数据并尽快处理它。

于 2009-01-08T01:07:50.817 回答
0

您说您尝试了“IP”,并且您可能通过指定 ProtocolType.Ip 来做到这一点,但我不知道这真正意味着什么(即我不知道在“幕后”选择了什么协议)使用 SocketType.Stream。

正如 casperOne 所说,如果您使用的是 TCP,请查看设置 SocketOptionName.NoDelay 是否对您有任何影响。

于 2009-01-08T00:59:43.267 回答