简体   繁体   English

在网络游戏中使用哪种方法正确发送/接收数据(UDP,但为什么不使用TCP)

[英]Which method to send/receive data properly in a network game (UDP, but why not TCP)

I have a C++ application with GUI that runs (on PC 1) just like a network game, and receives data packets from another computer (2) via WiFi (ad-hoc, so it's quite reliable) at fairly regular intervals (like 40ms), once per loop on program (2). 我有一个带有GUI的C ++应用程序,它就像在网络游戏上一样在PC 1上运行,并以相当固定的间隔(例如40毫秒)通过WiFi(即席,因此非常可靠)从另一台计算机(2)接收数据包,在程序(2)上每个循环一次。 I use send/read. 我使用发送/读取。

Here is the problem: 这是问题所在:
- Packets are not always fully sent (but apparently you can simply keep send() ing the remaining data until all is sent, and thats works well) -数据包并不总是被完全发送(但是显然您可以简单地使send()保留剩余的数据,直到所有数据都发送完为止,这很好用)
- More importantly , packets are stacked in the socket during (1)'s loop until the read() occurs, and then there is no way to distinguish packets in the big stream of data, or know if you were already in the middle of a packet. - 更重要的是 ,在(1)的循环期间,数据包会堆积在套接字中,直到发生read()为止,然后无法区分大数据流中的数据包,也无法知道您是否已经在中间一包。

I tried to fix this with ID headers (you find an ID as first bytes and you know the length of the packet), but I often get lost (unknown ID : we are not at the beginning of the packet) and am forced to ignore all the remaining data. 我尝试使用ID标头(您在第一个字节中找到一个ID,并且知道数据包的长度)来解决此问题,但是我经常迷路(未知ID:我们不在数据包的开头),被迫忽略所有剩余的数据。

So my question is: 所以我的问题是:
Why do packets stack? 为什么数据包会堆叠? (generally I have 400B of data whereas my packets are <100B long and fps (1) and (2) are not very different) (通常我有400B的数据,而我的数据包的长度小于100B,并且fps(1)和(2)差别不大)
How can I have a more reliable way to receive actual packets, say, 80% of packets (discarding packet loss, it's not a question of UDP/TCP)? 我如何有一种更可靠的方式来接收实际的数据包,例如80%的数据包(丢弃数据包丢失,这不是UDP / TCP的问题)?

Would a separate thread for receiving packets work? 一个单独的用于接收数据包的线程会起作用吗? (on (1), the server) (在(1)上,服务器)

How do real-time network games to that (including multiple client management)? 实时网络游戏如何做到这一点(包括多客户端管理)?

Thanks in advance. 提前致谢。

(Sorry I do not have the code here, but I tried to be as clear as I could) (对不起,我在这里没有代码,但是我尽力做到了清楚)

Well: 好:

1) UDP transfers MESSAGES, but is unreliable. 1)UDP传输消息,但不可靠。

2) TCP transfers BYTE STREAMS, and is reliable. 2)TCP传输字节流,并且可靠。

UDP cannot reliably transfer messages. UDP无法可靠地传输消息。 Anything more reliable requires a protocol on top of UDP. 任何更可靠的方法都需要在UDP之上的协议。

TCP cannot transfer messages unless they are one byte long. 除非消息长一字节,否则TCP无法传输消息。 Anything more complex requires a protocol on top of TCP. 任何更复杂的操作都需要TCP之上的协议。

  • Why do packets stack? 为什么数据包会堆叠? (generally I have 400B of data whereas my packets are <100B long and fps (1) and (2) are not very different) (通常我有400B的数据,而我的数据包的长度小于100B,并且fps(1)和(2)差别不大)

Because the time to send packets across the net varies, it typically does not make sense to send packets at a high rate, so most networking libraries (eg RakNet) will queue up packets and do a send every 10 ms. 由于通过网络发送数据包的时间各不相同,因此以高速率发送数据包通常没有意义,因此大多数网络库(例如RakNet)都会将数据包排队并每10毫秒发送一次。

In the case of TCP, there is Nagle's algorithm which is a more principled way of doing the same thing. 对于TCP,有Nagle算法,这是做同一件事的更原则的方法。 You can turn Nagle's off by setting the NO_DELAY TCP flag. 您可以通过设置NO_DELAY TCP标志来关闭Nagle。

  • How can I have a more reliable way to receive actual packets, say, 80% of packets (discarding packet loss, it's not a question of UDP/TCP)? 我如何有一种更可靠的方式来接收实际的数据包,例如80%的数据包(丢弃数据包丢失,这不是UDP / TCP的问题)?

If you use TCP, you will receive all of the packets and in the right order. 如果使用TCP,则将以正确的顺序接收所有数据包。 The penalty for using TCP is if a packet is dropped, the packets after it wait until that packet can be resent before they are processed. 使用TCP的代价是,如果数据包被丢弃,它之后的数据包将等待,直到该数据包可以重新发送后再进行处理。 This results in a noticeable delay, so any games that use TCP have sophisticated prediction techniques to hide this delay and other techniques to smoothly "catch up" once the missing packet arrives. 这会导致明显的延迟,因此,使用TCP的任何游戏都具有复杂的预测技术来隐藏此延迟,而其他技术则可以在丢失的数据包到达后平稳地“追赶”。

If you use UDP, you can implement a layer on top that gives you reliability but without the ordering if the order of the packets doesn't matter by sending a counter with each packet and having the receiver repeatedly notify the sender of gaps in the counts. 如果使用UDP,则可以在其上实现一个层,该层可提高可靠性,但如果数据包的顺序无关紧要,则无需排序,方法是为每个数据包发送一个计数器,并让接收方重复向发送方通知计数间隔。 You can also implement ordering by doing something similar. 您也可以通过执行类似的操作来实现排序。 Of course, if you enforce both, then you are creating your own TCP layer. 当然,如果同时执行这两个操作,那么您将创建自己的TCP层。 See http://www.jenkinssoftware.com/raknet/manual/reliabilitytypes.html for more details. 有关更多详细信息,请参见http://www.jenkinssoftware.com/raknet/manual/reliabilitytypes.html

What you describe is what would happen if you are using TCP without a protocol on top of it to structure your transmitted data. 您所描述的是,如果您在不使用TCP协议的基础上使用TCP来构造传输数据的情况下会发生什么。 Your idea of using an ID header and packet length is one such protocol. 您使用ID标头和数据包长度的想法就是这样一种协议。 If you send a 4-byte ID followed by a 4-byte length followed by X number of bytes, then the receiver knows that it has to read 4 bytes followed by 4 bytes followed by X bytes to receive a complete packet. 如果发送4字节ID,然后发送4字节长度,再发送X个字节,则接收方知道它必须先读取4个字节,再读取4个字节,再读取X个字节才能接收完整的数据包。 It doesn't get much simplier than that. 没有比这更简单的了。 The fact that you are still having problems reading packets with such a simple protocol suggests that your underlying socket reading code is flawed to begin with. 您仍然难以使用这种简单的协议读取数据包,这一事实表明您的底层套接字读取代码从一开始就存在缺陷。 Without seeing your actual code, it is difficult to tell you what you are doing wrong. 没有看到您的实际代码,很难告诉您您做错了什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM