Archived

This topic is now archived and is closed to further replies.

TCP or UDP?

This topic is 5108 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I begun work on a multiplayer space fighter earlier this year (boring I know, but its the first steps towards what I hope to one day be a more interesting massively multiplayer game) and ran into problems with the network programming part of the game. My question is this: which protocol is better for online games designed for a large number of players, TCP or UDP? I pretty much know the differences: TCP has guaranteed delivery, thus being slower, but UDP has poor reliability despite being faster. I have been researching this issue for a while, and the consensus seems split. I realize that you can implement your own packet delivery system with UDP, but I have not attempted this yet, although it seems like the correct answer. Does anyone who has written a MMOG care to share his/her thoughts on this? Thanks, Kevin P.S. Yes, I have written tetris. And then some. P.P.S. No, I am not new to network programming, just network programming in a game.

Share this post


Link to post
Share on other sites
RonHiler, that article has one of my favourite lines:

"TCP is evil. Don’t use TCP for a game. You would rather spend the rest of your life watching Titanic over and over in a theater full of 13 year old girls."

-------
Andrew
PlaneShift - A MMORPG in development.

Share this post


Link to post
Share on other sites
The only type of game I would use TCP for is RTS or other strategy games, because they don''t require super fast reaction time and reliability is a must. For other types of games, a custom UDP based protocol with selectable reliability is best.



Looking for a serious game project?
www.xgameproject.com

Share this post


Link to post
Share on other sites
Thanks all.

On a related note, how can I tell how calls to sendto() are split up into UDP packets? This seems important because UDP doesn't guarantee in order delivery, and it would be nice to know that a small quantum of data actually would be delivered as intended.

Edit:

I remember reading that article a while back, but it makes more sense now that I have learned more about network programming. What do people think about this part though:
"Our solution was simple and surprisingly effective. Every packet would send copy of the last packet. This way if a packet were dropped, a copy of it would arrive with the next packet, and we could continue on our merry way".

Is this a good approach, rather than actually resending packets, or perhaps in addition to?

[edited by - kevmo on December 16, 2003 11:33:56 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by kevmo
Is this a good approach, rather than actually resending packets, or perhaps in addition to?

It''s one approach. It all depends on your requirements. The way they use is fine if it is absolutely necessary that each and every packet gets to its destination and in order (I presume they use some form of incremental ID value to order the packets). If your game has that requirement and can deal with the double bandwidth size (and remember with UDP you''re limited to about 512 bytes per packet for best results, which means with the double packeting you''re now down to 256 bytes of new data minus the header size), then yeah, it''s a pretty good method.

On the other hand, many games (mine for instance) don''t have this requirement. I find that certain types of packets need ordering *within themselves* (not necessarily with other kinds of packets), and many types are not critical to even get there as long as there are more of the same type on the way. Because of this, my implementation selectively (on a per packet type basis) allows for ordering of packets of a given type and/or reliability (which amounts to nothing more than buffering the packet data, ack packets and resends after a timeout period). This approach is commonly used in most UDP games, I think.

Share this post


Link to post
Share on other sites
quote:

On a related note, how can I tell how calls to sendto() are split up into UDP packets?



They aren't. One UDP packet per sendto(), that's it.

quote:

The only type of game I would use TCP for is RTS or other strategy games, because they don't require super fast reaction time and reliability is a must.



Actually, that is questionable. Suppose the RTS uses a server approach where the actual unit movements are broadcast from a server to the clients (as opposed to synchronized simulation), it doesn't matter if one update from the server gets dropped, since the next update will fix it anyway.
Even if you are using synchronized simulation, I'd think twice about using TCP. It's simply hard to tweak and control (e.g. consider resending timeouts etc.).

If any type of game is suited for TCP, it would be round-based games.

cu,
Prefect

[edited by - Prefect on December 17, 2003 6:29:42 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Prefect
They aren't. One UDP packet per sendto(), that's it.



Thats what I was afraid of. The thing that gets me is that I was taught to write a send() function similar to the following:


sendfunction(buf, size) {
bytessent = 0
while(bytessent<size)
bytessent += send(buf+bytessent, size-bytessent)
}


This way, the whole message gets sent in case send/sendto doesnt send all of the bytes. However, if there is only one packet per sendto, and packets aren't in order, couldn't that mess up some messages? Under what conditions would sendto not return that it sent all the bytes? Just when the size given is greater than 512 bytes less header size?

[edited by - kevmo on December 17, 2003 7:56:46 PM]

Share this post


Link to post
Share on other sites
quote:


quote:
--------------------------------------------------------------------------------

The only type of game I would use TCP for is RTS or other strategy games, because they don't require super fast reaction time and reliability is a must.

--------------------------------------------------------------------------------


Actually, that is questionable. Suppose the RTS uses a server approach where the actual unit movements are broadcast from a server to the clients (as opposed to synchronized simulation), it doesn't matter if one update from the server gets dropped, since the next update will fix it anyway.
Even if you are using synchronized simulation, I'd think twice about using TCP. It's simply hard to tweak and control (e.g. consider resending timeouts etc.).

If any type of game is suited for TCP, it would be round-based games.




Thats not true at all. RTS games usually involve endpoint based movement (ie: move this unit or this group of units from here to there). Such updates can be only sent once, saving bandwidth by avoiding to constantly send movement updates. RTS games also do not require a very fast latency, so TCP would be fine and actually advisable for RTS games. In such a system, the server also has much less to worry about, it simply checks the validity of client commands and broadcasts them once.

TCP would also be advisable for round based games of course.

I'm using my own UDP based protocol for my FPS game engine, but TCP definitely has a use in game development, its just more suited to specific game styles. Saying that TCP is evil and makes no sense at all for games simply shows a lack of knoweledge of real world networking and game development... There is no universal solution.



Looking for a serious game project?
www.xgameproject.com

[edited by - Max_Payne on December 17, 2003 11:21:01 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by kevmo
Under what conditions would sendto not return that it sent all the bytes? Just when the size given is greater than 512 bytes less header size?

Under no conditions, if I understand your question right. If you are using a blocking socket (usually a bad idea), the call will block until the enitre packet is sent out. If you are using some sort of completion notification (better idea) the call will return immediately, and you''ll get a completion notification once the whole thing has gone.

For that reason, there is no need for a while loop like you use in a send call.

My send function is very simple, it just sets up a couple of class variables and sends the buffer. It''s basically just fire and forget.


int BufferClass::SendBuffer(SOCKET *Socket, DWORD Address, u_short Port)
{
//set up the output socket info
Operation = OP_WRITE;
ZeroMemory(&Overlapped, sizeof(WSAOVERLAPPED));
ClientAddress.sin_family = AF_INET;
ClientAddress.sin_addr.s_addr = Address;
ClientAddress.sin_port = Port;
ClientAddressSize = sizeof(sockaddr);
Flags = 0;

return WSASendTo(*Socket, &WSABuf, 1, &NumBytes, Flags, (sockaddr*)&ClientAddress, ClientAddressSize, &Overlapped, NULL);
}


Max:
No one is saying TCP is useless. Indeed, it is quite appropriate for most any turn based game. I even agree you *might* get away with it for an RTS depending on the game setup. But it is mostly inappropriate for games in general. Saying otherwise is just being unneccesarily contrary and argumentative.

Share this post


Link to post
Share on other sites
Hi Kevin, I agree completely with the earlier posters, UDP is definately the way to go for any kind of game which requires real-time responsiveness. I''m currently writing a space combat MMOG myself, designed to be scalable over multiple servers it''s definately a good introduction to the intricacies of network programming

I notice you were having problems with send functions etc. with UDP, you can take a look at the network library I wrote for my project (which is a fairly early version and needs some extra features adding and some tidying up, but it works, and has all the essential components of a UDP-based reliable networking protocol). It''s available at http://www.clearchaos.com/netlib.php (although the site is down sometimes and bandwidth is fairly limited, since I''m hosting it on my own connection currently).

To comment on your idea of sending redundant copies of each packet; this could be a viable method in a game with few players, but given that most of the time you''ll be using twice the bandwidth you strictly need, may be a bad idea for games with many players, due to the cost and limited availability of bandwidth. A better solution might be to resend packets to a client if an acknowledgement for them is not received after a given amount of time (for instance twice the clients ping, or 500ms, or a time you devise using some other algorithm). This is especially true since there is no guarantee with your method that a client would receive a packet the second time, so surely some reliability method similar to the above would need to be implemented anyway?

Hope that''s of some help.

Share this post


Link to post
Share on other sites
quote:
it''s definately a good introduction to the intricacies of network programming


Your telling me - I had a working (well not really in the end) version of mine that allowed players to fly around and see each other, and I discovered all sorts of subtlies I hadn''t seen in any of the articles here on gamedev. I scrapped the code in favor of a rewrite, and then came schoolwork, and so here I am now trying to plan things out better before I try again.

Share this post


Link to post
Share on other sites
The sample chapter of Mud Game Programming, on the front page of gamedev (click), goes over the topic quite well. As previous posters have mentioned, TCP is more suited for games where packet accuracy is more important than speed such as RTS, and MUDs. UDP would be more suited for fast paced games like FPS and action games.

[edited by - vangelis on December 18, 2003 1:47:40 AM]

Share this post


Link to post
Share on other sites
512 seems a bit small.

Ethernet II''s MTU is 1518 bytes (1526 bytes on the wire)
7 pre-amble, 1 start, and then ethernet packet

The ethernet II header is 14 bytes and there''s a 4 byte check-sum at the end.
6 src, 6 dest, 2 type, pay-load, 4 cs
(src & dst are your NIC''s MACs)
Maximum pay-load thus is 1500, and the minimum payload is 46 bytes.

IP header is typically 20 bytes (could be larger with options, but these are less commonly used - e.g. multi-casting), a bunch of crap followed by the source and destination IP addresses.

Remaining pay-load is 26 to 1480 bytes.

UDP header is an additional 8 bytes; src & dst ports, length, & a check-sum.
That leaves 1432 bytes for the payload max, and 18 bytes minimum.

UDP on ethernet II has a 50 byte overhead; to send 1 to 18 bytes of UDP data, you have to put 68 bytes on the wire.

In a few days I''ll be writing some UDP code, and I''ll check out how much data I can send over the LAN, WAN, & internet. I expect it to be 1432 bytes.

If the data goes through some crappy token-ring or arc-net then then I don''t know the MTU. Today, nearly everything uses ethernet locally (I guess I should update myself to 802.11 - what''s the MTU on the wireless ethernet?).

Share this post


Link to post
Share on other sites
quote:
Original post by Psychor
Hi Kevin, I agree completely with the earlier posters, UDP is definately the way to go for any kind of game which requires real-time responsiveness. I''m currently writing a space combat MMOG myself, designed to be scalable over multiple servers it''s definately a good introduction to the intricacies of network programming

I notice you were having problems with send functions etc. with UDP, you can take a look at the network library I wrote for my project (which is a fairly early version and needs some extra features adding and some tidying up, but it works, and has all the essential components of a UDP-based reliable networking protocol). It''s available at http://www.clearchaos.com/netlib.php (although the site is down sometimes and bandwidth is fairly limited, since I''m hosting it on my own connection currently).

To comment on your idea of sending redundant copies of each packet; this could be a viable method in a game with few players, but given that most of the time you''ll be using twice the bandwidth you strictly need, may be a bad idea for games with many players, due to the cost and limited availability of bandwidth. A better solution might be to resend packets to a client if an acknowledgement for them is not received after a given amount of time (for instance twice the clients ping, or 500ms, or a time you devise using some other algorithm). This is especially true since there is no guarantee with your method that a client would receive a packet the second time, so surely some reliability method similar to the above would need to be implemented anyway?

Hope that''s of some help.




I started reading through your netlib, and one thing really jumped out at me:

#define MAXPACKETSIZE 1400


Despite the last posters analysis leading to 1400 being a very reasonable number, I would feel a lot better if that were a constant based on getsockopt().

On the other hand, I like how you structured your different kinds of messages (RELIABLE X ORDERED).

Share this post


Link to post
Share on other sites
quote:
Original post by RonHiler
quote:
Original post by kevmo
Under what conditions would sendto not return that it sent all the bytes? Just when the size given is greater than 512 bytes less header size?

Under no conditions


I found the resource where I got the notion that partial sends could occur: http://www.ecst.csuchico.edu/~beej/guide/net/html/advanced.html#sendall

Is that just plain wrong?

Share this post


Link to post
Share on other sites
To kevmo:
There is a difference between send and sendto. Assuming you use send for TCP und sendto for UDP: If sendto would only send a little part of the message you would be in big trouble because UDP is unreliable. It does not help do send the rest of the Packet with another call to sendto because UDP does not garante that the Packets will be recived in order and therefor you will have trouble putting the package together again.
With send (TCP) it is a whole different story. TCP is a stream orientated Protokol and messages will be recived in the same order. So if send does not send everyting, you can send the rest with another call to send and you wont have any trouble putting it together on the reciver side (in fact, the reciver should not see any difference).
The bottom line is: If sendto would only send parts of the message (which can happen with send), you would be in big trouble. With send, it is no problem because TCP garuantes that the packages will arrive in order.

Sorry if may english is not to good, but I hope I was able to make clear to you what the difference is.

Share this post


Link to post
Share on other sites
quote:
Original post by Magmai Kai Holmlor
512 seems a bit small.


Thanks for the analysis Magmai, that''s about the most comprehensive breakdown of a UDP packet I''ve seen I keep seeing conflicting information about this topic. I know that UDP packets can be bigger than 512 bytes, but from what I understand anything above that runs the risk of the packet splitting apart on its way to the destination, thus doubling or tripling the chances of packet loss. That''s why I (generally) keep mine below that level (easy to do in all cases, I rarely send huge chunks of data at a time, my average packet size runs more like 100-200 bytes for most things). Is that incorrect?

quote:
Original post by kevmo
I found the resource where I got the notion that partial sends could occur: http://www.ecst.csuchico.edu/~beej/guide/net/html/advanced.html#sendall


No, but he''s talking about TCP. The method he uses is the correct one for TCP send calls. For UDP, it wouldn''t be right.

Share this post


Link to post
Share on other sites
quote:
Original post by kevmo
Despite the last posters analysis leading to 1400 being a very reasonable number, I would feel a lot better if that were a constant based on getsockopt().



The problem is that getsockopt() can only tell you about the local network. Anything beyond that (additional restrictions imposed by routers en route) will not be returned by getsockopt(). If you do want to find out about the maximum packet size at runtime, you''d have to try sending successively bigger/smaller packets and test which one get through without getting fragmented.
The problem with this is that getsockopt

cu,
Prefect

Share this post


Link to post
Share on other sites

Yes, there are cases where sendto() will NOT send the entire packet you give it. IPv4 only has a payload size range of 16 bits. If you try to send something larger, you will get EMSGSIZE. If you try to send something larger than local MTU, you also get EMSGSIZE. IPv4 only guarantees that data packets of size 548 bytes will traverse all IP networks unfragmented. 1400 is reasonable in most cases, but it is not guaranteed by any specification unless you are restricting multi-play to ethernet. The derivation of 548 can be found various places around the net, it''s not a magic number pulled out of thin air.

The TCP/UDP decision should not be based solely on game genre. I''m working on a RTS-like game that requires UDP. TCP is not sufficient. There really is no reason to mix TCP and UDP during normal gameplay unless you are using 3rd party libraries that require such an implementation. Using both just adds complexity to your design with zero gain.

fingh.

Share this post


Link to post
Share on other sites