1
votes

I have to write a program using UDP sockets and I'm having trouble understanding what should I do in a scenario I have.

I have a server and a client. The server receives datagrams on an INADDR_ANY socket and for each unique client that shows up, it will sendto() a lot of information to. Each client also sends data periodically to the server.

For each client that contacts the listening socket, lets call it 0, I create a separate socket for, so I can send data to it without clogging socket 0. What I want to do is move all communication with a specific client to the new socket. Can I do that? The goal is to make the communication easier, efficient and avoid clogging any sockets.

So questions I failed to find answers for are:

  • can I recv data from that socket from that specific client?
  • If not, won't having all the clients write to socket 0 clog it if I won't do recvfrom often enough?
  • If it's possible to recv data from a specific client on a separate socket, will that data come to BOTH socket 0 and the specific socket?

I know that TCP would work better for this but I have to use UDP. How should I do this? Is there an accepted "standard" of handling such situations?

Comment: I have a feeling I am misunderstanding UDP sockets but there's really very little tutorials on it when compared to TCP.

2
There is really no such thing as 'clogging socket 0'. If the sends are going to get clogged, it won't matter how many sockets you have. UDP servers are best implemented with a single socket.user207421
@EJP Really? I mean sockets have a restricted amount of memory. If a socket is full, a sendto() to it block or fail if non-blocking, right? It just feels logical to me to create a UDP socket per client. What's wrong with my logic?m_highlanderish
Unlike TCP sockets, UDP sockets will always send data out as fast as the network interface(s) will accept it. Therefore in general you don't need e.g. two UDP sockets; you could instead create a single UDP socket with twice the amount of SO_SNDBUF buffer space.Jeremy Friesner
@m_highlanderish Sockets have socket send and receive buffers, whose size you can control.user207421

2 Answers

5
votes

What I want to do is move all communication with a specific client to the new socket. Can I do that?

You could create a new UDP socket, bind() it to a different port, and then instruct the client to start sending traffic to the new socket's port instead of the usual one; but note that there isn't really any advantage to be gained by doing that.

If not, won't having all the clients write to socket 0 clog it if I won't do recvfrom often enough?

Yes, but the usual solution that is to call recvfrom() often enough to keep up with the flow of incoming traffic, and/or to increase its SO_RECVBUF buffer size to make its incoming-data buffer big enough that it is inlikely to become full. One way to ensure recvfrom() is called often enough is to create a separate thread that does nothing but call recvfrom() in a loop and then hand off the data to another thread for more intensive processing. Run this network thread at higher priority if possible to make sure it doesn't get held off of the CPU by other threads.

If it's possible to recv data from a specific client on a separate socket, will that data come to BOTH socket 0 and the specific socket?

If you have two threads both calling recvfrom() on the same socket, then any given incoming UDP packet will be delivered to either one thread or the other, and it's impossible to predict which thread will receive which packet -- it will just be luck of the draw depending on what is the next packet in the socket's incoming buffer at the instant a particular thread calls recvfrom() on it. In general having multiple threads accessing a single socket is not a recommended design.

I know that TCP would work better for this but I have to use UDP. How should I do this? Is there an accepted "standard" of handling such situations?

I don't know about what is "standard", but I usually have a dedicated I/O thread that does nothing but read from (and if necessary, write to) the UDP socket. It sets the UDP socket to non-blocking mode, then loops around select() to recvfrom() any incoming UDP packets and append (in a thread-safe manner) both the incoming packet's data and its source-address/port info to a FIFO queue for other (less time-sensitive) threads to take out and work on later. That way even if a packet (or series or packets) takes a relatively long time to process, the result won't be that packets get dropped (although it might temporarily increase RAM usage as the FIFO grows larger)

0
votes

@ Jeremy Friesner: You wrote: "...and even then my intuition is that it will be non-deterministic/unpredictable which of the two sockets receives any particular packet -- and if your connect()'d socket receives someone else's packet, I suspect the packet will get dropped/filtered". Exactly this I investigated in Linux and lwIP with the result: the later created socket (with the higher fd number) is the receiving one while the other do not receive.