Advertisement

Reading multiple datagrams from UDP socket

Started by August 27, 2016 09:49 AM
6 comments, last by wodinoneeye 8 years, 2 months ago

Hello!

The call recvfrom reads messages from udp socket one by one, so to read 10 messages you should call recvfrom 10 times. Are there any methods or, may be, some low-level commands to read all the messages at once into a buffer?

UDP is about datagrams. It has no conception above that, especially not how to concat datagrams nor how to distinguish them after concatenation.

However, it is not clear to me *why* you want to do so. What does "all the messages" mean exactly? A sequence of messages from the same source? A soap of messages from different sources? What should happen if one of them is missed on transmission? Such questions need to be handled as well.

IMHO we're speaking of stuff belonging to the application protocol layer!?

Advertisement
If avoiding syscall overhead is your goal, you have to move away from the standard socket interface into platform-specific extensions. For example, you can use recvmmsg under Linux to that effect (note the double "mm", this is not a spelling error). Works reliably. Similarly, WSARecvFrom under Windows lets you specify more than one receive buffer, which should (I've not tested, no need) work that way, too.
WSARecvFrom allows multiple buffers for purposes of scatter/gather, but only returns one message at a time.
Also, this is pretty clear, because it only returns one socket address.
Similarly, recvmmsg() only really makes sense for connected sockets, because it, also, doesn't return the addresses of any of the messages.
For the common use case of a UDP server talking to more than one client on the same socket, neither of those functions are appropriate.
enum Bool { True, False, FileNotFound };

WSARecvFrom allows multiple buffers for purposes of scatter/gather, but only returns one message at a time. Also, this is pretty clear, because it only returns one socket address. Similarly, recvmmsg() only really makes sense for connected sockets, because it, also, doesn't return the addresses of any of the messages.
For the common use case of a UDP server talking to more than one client on the same socket, neither of those functions are appropriate.

I've never tried WSARecvFrom, as stated. However, recvmmsg certainly works for datagrams from different addresses. It returns a pointer to a return-value sized array of mmsghdr structures, each of which contains a msg_hdr structure and the receive length for that particular message. The msg_hdr structure contains a member msg_name, which is the originating address.

The msg_hdr structure contains a member msg_name, which is the originating address


You're right; I missed that the recvmmsg mmsghdr pointer would have multiple entries.
Thanks for pointing that out!
WSARecvFrom unfortunately does not do the same thing.
enum Bool { True, False, FileNotFound };
Advertisement

Hello!

The call recvfrom reads messages from udp socket one by one, so to read 10 messages you should call recvfrom 10 times. Are there any methods or, may be, some low-level commands to read all the messages at once into a buffer?

I think you're asking the wrong question. My guess is you worry about multiple clients sending UDP messages to a server, and you won't be able to read them all out in a timely manner for some reason.

I think what you really want to do is read UDP messages as they arrive (considering you won't really have 10 UDP packets arriving at the "same time"), so you should use select() (or some other method of notification) to signal you have data to be read from the UDP socket. At that point, it's just a matter of calling recvfrom() as you get notified of a packet arriving, and determining which client sent the data.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

It depends on the throughput expected.
The cost of a system call is on the order of 1 microsecond, so at 1 million datagrams, you will saturate one core just reading.
And if you need locking to hand off work to other threds, you may be multiplying the number of system calls.

Of course, you'd need 10 Gbit networking to acctuall ge million packets across in a second, and that in turn assumes your networking driver and hardware are 100% efficient...
But there exists systems where paying 1/20th as many syscalls by reading 20 incoming packets at a time actually does reduce CPU load!
The question is whether the OP is at that scale or not -- we have no way of knowing.
enum Bool { True, False, FileNotFound };

It depends on the throughput expected.
...
The question is whether the OP is at that scale or not -- we have no way of knowing.

hplus, you know more about networking than me, no doubt, but, reading his initial question, I feel pretty safe in assuming he isn't in need of that kind of throughput and it's is more of a beginner networking question.

Either way, we now have both bases covered.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

There is some middle processing (often done in a separate thread) where all the "Reliability" issues (if any) are handled and channeling/organizing info down different processing streams (ie- looking for client signals like close/byebye msgs versus the running data streams, or multiple packet block completion ) can be done before it gets to the higher level game processing.

If you have multiple packets making up one message then you need data markings within the packets to allow the receiver to determine if the whole message HAS arrived (intact) to then be passed-on and actioned (at higher level or whatever).

--------------------------------------------[size="1"]Ratings are Opinion, not Fact

This topic is closed to new replies.

Advertisement