How do I handle recvfrom?

Started by
15 comments, last by wodinoneeye 15 years, 9 months ago
So I can't depend on that the OS will send all my data or receive all my data with send and recv methods. Beej describes a solution in his guide about calling send multiple times until all data have been sent. I can do that with sendto as well. But what about recvfrom? In Beej's example, he assumes that all data comes in order and that they always arrive. How are recvfrom beeing handled in a game that uses UDP? Another question, how should I keep the list of clients in the server? I mean, I need to search two things in this client list. The IP address and the player position. I need the IP address so I can update the player after receiving data on the server. I need the player pos in order to know which players that needs the updated information (so players that aren't near the affected action won't get the message).
Advertisement
Typically, one designs or uses a protocol on top of UDP which allows the sender know which packets arrived, and the receiver know in which order they were sent. There are a number of libraries that implement this for you. Check to Forum FAQ, Questions 7 and 8 in particular.
If I understand this correctly, I have to use reliable UDP if the package exceeds a certain size? How can I determine how much I can send and recv without the package being divided?
Quote:Original post by RandomPixel
If I understand this correctly, I have to use reliable UDP if the package exceeds a certain size? How can I determine how much I can send and recv without the package being divided?


You need to use some form of reliable transfer, if you want to transfer data reliably (without loss, knowing which packets got lost, transferring data in order).

The maximum data you can send without fragmentation depends, for practical purposes, on the smallest MTU between peers. Usually that's in 530-1500 byte range.

UDP gives you no guarantees of any kind. If you need any guarantee for anything, you need to implement it yourself.
I understand that. I'm not actually looking for guarantee that all packets arrive. I just wanted to understand how to implement recvfrom.

For example, if the client sends these packets:
packet 1: MOV x1 y1
packet 2: TURN d
packet 3: MOV x2 y2

Then the server will maybe get 2 packets:
MOV x2 y2
MOV x1 y1

I can use a timestamp to remove old packets. But is it possible for recv to get a package that is both packet 3 and packet 1 in one:
MOV x2 y2 MOV x1 y1

or even getting packet 3 and the last part of packet 1:
MOV x2 y2 y1

How can I handle stuff like that?
Quote:Original post by RandomPixel
I understand that. I'm not actually looking for guarantee that all packets arrive. I just wanted to understand how to implement recvfrom.


recvfrom under UDP has only one use - it reads from network buffer for whatever is in there. Anything else, you need to implement your own logic.

Quote:I can use a timestamp to remove old packets. But is it possible for recv to get a package that is both packet 3 and packet 1 in one:


It's possible, if you implement that.

Quote:How can I handle stuff like that?


send and recv handle with a sequence of bytes, and absolutely nothing more.

If you want to pack multiple logical units into one, you implement that yourself, by constructing buffer appropriately.

If you need reliable transport, you add a sequence number to each packet. This way, you know which went missing. You then send a packet requesting resend. When a packet is received, you send ack notifying which packet arrived. If some packets don't arrive, you resend them. If some arrive multiple times, you discard them.

An example of reliable transport implementation is covered by TCP's implementation, as well as many networking courses (implementation of reliable UDP is a common excercise for these). Another topic of interest here is serialization.

But there is a lot of ground to cover just to achieve efficient, yet robust UDP-based communication.
Thanks! I think I understand now.

So basically. If I send the package "MOV x1 x2" and if it arrives on the server, calling recvfrom on the server will get exactly the package "MOV x1 x2" and not part of other packets.

As long as I'm not sending more than 530 bytes, I will get the entire package with recvfrom just as the package was when sending it with sendto.
Quote:Original post by RandomPixel
Thanks! I think I understand now.

So basically. If I send the package "MOV x1 x2" and if it arrives on the server, calling recvfrom on the server will get exactly the package "MOV x1 x2" and not part of other packets.


UDP is packet based, and packets are defined by what you sendto(). So yes.

But it's customary for UDP protocol implementations to use some custom checksum, perhaps based on peer's IP/Port, to ensure the contents are valid, and of appropriate protocol. Even if using custom ports, there's a lot of noise, and receiving unrelated random packets is not uncommon.

Other than that, the documentation on sendto and recvfrom is quite comprehensive.
Quote:Original post by RandomPixel
As long as I'm not sending more than 530 bytes, I will get the entire package with recvfrom just as the package was when sending it with sendto.
You'll get that if you send more, too.
UDP has almost no guarantees, but it does have one guarantee. A datagram is either dropped/lost or delivered completely. If you exceed the MTU, the packet will get fragmented on the IP layer. If only one of the fragments is lost, the entire UDP datagram is discarded. If they all arrive, the whole UDP datagram will be in your buffer when recvfrom() returns.
In theory, you could write a server that never uses anything like select/poll, and simply blocks in recvfrom() inside an endless loop. Whenever data arrives, it will wake up, do some work (maybe send a reply), and block again. If periodic updates are needed, that would obviously have to happen from another thread then, but just for the principle of a really simplistic server, it's quite cool, I think.
Compare that to the pain of managing 500 or 1000 sockets, and passing them to poll (or anything similar) just to know when something happens on a TCP server.
Quote:Original post by Antheus
But it's customary for UDP protocol implementations to use some custom checksum, perhaps based on peer's IP/Port, to ensure the contents are valid, and of appropriate protocol. Even if using custom ports, there's a lot of noise, and receiving unrelated random packets is not uncommon.


I was thinking about doing some kind of validation to check that the package I get is valid to my game. In case of cheating and stuff like that. Like a unique ID for the client or maybe check so the ip addresses matches.

Quote:Original post by samoth
You'll get that if you send more, too.
UDP has almost no guarantees, but it does have one guarantee. A datagram is either dropped/lost or delivered completely. If you exceed the MTU, the packet will get fragmented on the IP layer. If only one of the fragments is lost, the entire UDP datagram is discarded. If they all arrive, the whole UDP datagram will be in your buffer when recvfrom() returns.


Oh, that's even easier. So no matter how big the package is I use in the sendto method, if it arrives I get the exact package in recvfrom.

This topic is closed to new replies.

Advertisement