当您需要可靠的 UDP 时,您使用什么?

如果您遇到 TCP 连接可能太慢而 UDP 连接可能太不可靠的情况,您会使用什么?有各种各样的标准可靠的 UDP 协议在那里,你有什么经验与他们?

请讨论每个答复一个协议,如果有人已经提到了你使用的一个,然后考虑投票他们,并使用一个评论,以详细说明,如果需要。

我对这里的各种选项感兴趣,其中 TCP 位于规模的一端,而 UDP 位于另一端。各种可靠的 UDP 选项都是可用的,每个选项都为 UDP 带来了 TCP 的一些元素。

我知道 TCP 通常是正确的选择,但是列出一个替代方案的列表通常有助于帮助人们得出这个结论。像 Enet,RUDP,等等这些建立在 UDP 之上的东西有各种各样的优点和缺点,你用过它们吗,你的经验是什么?

为了避免疑问,没有更多的信息,这是一个假设性的问题,我希望这个问题能够引出一个回答清单,详细列出需要做出决定的人可以选择的各种方案和备选方案。

74070 次浏览

ENET - http://enet.bespin.org/

I've worked with ENET as a reliable UDP protocol and written an asynchronous sockets friendly version for a client of mine who is using it in their servers. It works quite nicely but I don't like the overhead that the peer to peer ping adds to otherwise idle connections; when you have lots of connections pinging all of them regularly is a lot of busy work.

ENET gives you the option to send multiple 'channels' of data and for the data sent to be unreliable, reliable or sequenced. It also includes the aforementioned peer to peer ping which acts as a keep alive.

It's difficult to answer this question without some additional information on the domain of the problem. For example, what volume of data are you using? How often? What is the nature of the data? (eg. is it unique, one off data? Or is it a stream of sample data? etc.) What platform are you developing for? (eg. desktop/server/embedded) To determine what you mean by "too slow", what network medium are you using?

But in (very!) general terms I think you're going to have to try really hard to beat tcp for speed, unless you can make some hard assumptions about the data that you're trying to send.

For example, if the data that you're trying to send is such that you can tolerate the loss of a single packet (eg. regularly sampled data where the sampling rate is many times higher than the bandwidth of the signal) then you can probably sacrifice some reliability of transmission by ensuring that you can detect data corruption (eg. through the use of a good crc)

But if you cannot tolerate the loss of a single packet, then you're going to have to start introducing the types of techniques for reliability that tcp already has. And, without putting in a reasonable amount of work, you may find that you're starting to build those elements into a user-space solution with all of the inherent speed issues to go with it.

What about SCTP. It's a standard protocol by the IETF (RFC 4960)

It has chunking capability which could help for speed.

Update: a comparison between TCP and SCTP shows that the performances are comparable unless two interfaces can be used.

Update: a nice introductory article.

If you have a situation where a TCP connection is potentially too slow and a UDP 'connection' is potentially too unreliable what do you use? There are various standard reliable UDP protocols out there, what experiences do you have with them?

The key word in your sentence is 'potentially'. I think you really need to prove to yourself that TCP is, in fact, too slow for your needs if you need reliability in your protocol.

If you want to get reliability out of UDP then you're basically going to be re-implementing some of TCP's features on top of UDP which will probably make things slower than just using TCP in the first place.

Did you consider compressing your data ?

As stated above, we lack information about the exact nature of your problem, but compressing the data to transport them could help.

As others have pointed out, your question is very general, and whether or not something is 'faster' than TCP depends a lot on the type of application.

TCP is generally as fast as it gets for reliable streaming of data from one host to another. However, if your application does a lot of small bursts of traffic and waiting for responses, UDP may be more appropriate to minimize latency.

There is an easy middle ground. Nagle's algorithm is the part of TCP that helps ensure that the sender doesn't overwhelm the receiver of a large stream of data, resulting in congestion and packet loss.

If you need the reliable, in-order delivery of TCP, and also the fast response of UDP, and don't need to worry about congestion from sending large streams of data, you can disable Nagle's algorithm:

int opt = -1;
if (setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)))
printf("Error disabling Nagle's algorithm.\n");

RUDP - Reliable User Datagram Protocol

This provides:

  • Acknowledgment of received packets
  • Windowing and congestion control
  • Retransmission of lost packets
  • Overbuffering (Faster than real-time streaming)

It seems slightly more configurable with regards to keep alives then ENet but it doesn't give you as many options (i.e. all data is reliable and sequenced not just the bits that you decide should be). It looks fairly straight forward to implement.

We have some defense industry customers that use UDT (UDP-based Data Transfer) (see http://udt.sourceforge.net/) and are very happy with it. I see that is has a friendly BSD license as well.

May be RFC 5405, "Unicast UDP Usage Guidelines for Application Designers" will be useful for you.

Protocol DCCP, standardized in RFC 4340, "Datagram Congestion Control Protocol" may be what you are looking for.

It seems implemented in Linux.

RUDP. Many socket servers for games implement something similar.

Anyone who decides that the list above isn't enough and that they want to develop their OWN reliable UDP should definitely take a look at the Google QUIC spec as this covers lots of complicated corner cases and potential denial of service attacks. I haven't played with an implementation of this yet, and you may not want or need everything that it provides, but the document is well worth reading before embarking on a new "reliable" UDP design.

A good jumping off point for QUIC is here, over at the Chromium Blog.

The current QUIC design document can be found here.

The best way to achieve reliability using UDP is to build the reliability in the application program itself( for example, by adding acknowledgment and retransmission mechanisms)

It is hard to give a universal answer to the question but the best way is probably not to stay on the line "between TCP and UDP" but rather to go sideways :).

A bit more detailed explanation:

If an application needs to get a confirmation response for every piece of data it transmits then TCP is pretty much as fast as it gets (especially if your messages are much smaller than optimal MTU for your connection) and if you need to send periodic data that gets expired the moment you send it out then raw UDP is the best choice for many reasons but not particularly for speed as well.

Reliability is a more complex question, it is somewhat relative in both cases and it always depends on a specific application. For a simple example if you unplug the internet cable from your router then good luck keeping reliably delivering anything with TCP. And what even worse is that if you don't do something about it in your code then your OS will most likely just block your application for a couple of minutes before indicating an error and in many cases this delay is just not acceptable as well.

So the question with conventional network protocols is generally not really about speed or reliability but rather about convenience. It is about getting some features of TCP (automatic congestion control, automatic transmission unit size adjustment, automatic retransmission, basic connection management, ...) while also getting at least some of the important and useful features it misses (message boundaries - the most important one, connection quality monitoring, multiple streams within a connection, etc) and not having to implement it yourself.

From my point of view SCTP now looks like the best universal choice but it is not very popular and the only realistic way to reliably pass it across the Internet of today is still to wrap it inside UDP (probably using sctplib). It is also still a relatively basic and compact solution and for some applications it may still be not sufficient by itself.

As for the more advanced options, in some of the projects we used ZeroMQ and it worked just fine. This is a much more of a complete solution, not just a network protocol (under the hood it supports TCP, UDP, a couple of higher level protocols and some local IPC mechanisms to actually deliver messages). Since a couple of releases its initial developer has switched his attention to his new NanoMSG and currently the newest NNG libraries. It is not as thoroughly developed and tested and it is not very popular but someday it may change. If you don't mind the CPU overhead and some network bandwidth loss then some of the libraries might work for you. There are some other network-oriented message exchange libraries available as well.

You should check MoldUDP, which has been around for decades and it is used by Nasdaq's ITCH market data feed. Our messaging system CoralSequencer uses it to implement a reliable multicast event-stream from a central process.

Disclaimer: I'm one of the developers of CoralSequencer