1

So, I'm creating a server in C which uses UDP, and I want to listen for incoming packets from many sources. Therefore, when I call ssize_t recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict), the 5th parameter, that which contains the sender's information, may vary.

Is there a way to receive the packets without knowing each individual client's address information? And, is this possible with C's library?

Here's my code:

int file_descriptor;
char data[1024];
int bytes_recved;
sockaddr_in iDontKnow;
socklen_t addr_len = sizeof(iDontKnow);
if ((bytes_recved = recvfrom(file_descriptor, data, strlen(data), 0, (struct sockaddr*)&iDontKnow, &addr_len)) < 0) {
    perror("Failed to receive data");
}

I noticed that when receiving data with Java's DatagramSocket and DatagramPacket classes, the DatagramSocket's receive function took in a parameter of type DatagramPacket. This DatagramPacket, however, only held the object in which to place the data. So, why does C's implementation of UDP receiving require that you know the sender's information?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Jerome Carter
  • 237
  • 1
  • 4
  • 18
  • 1
    The very code you showed receives packets without knowing the individual client's address information! Your code doesn't need to know the sender's information (you never populate `iDontKnow` with anything) and it will work just fine. – David Schwartz Mar 01 '17 at 06:28

4 Answers4

5

Is there a way to receive the packets without knowing each individual client's address information?

Well, you don't need to know the sender information beforehand, anyway. Once a packet is received, the sender information (if available) will be stored into address.

From the man page,

ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
                   int flags, struct sockaddr *restrict address,
                   socklen_t *restrict address_len);

[...] If the address argument is not a null pointer and the protocol provides the source address of messages, the source address of the received message shall be stored in the sockaddr structure pointed to by the address argument, and the length of this address shall be stored in the object pointed to by the address_len argument.

Regarding the why part, in case of connectionless sockets, unless you know of the sender address for a packet in a communication, you cannot reply or respond to the sender. So, it is required to know the sender info specifically in connectionless mode and there comes recvfrom() which, along with the received data, gives us the info about the sender, also.


EDIT:

In your code

recvfrom(file_descriptor, data, strlen(data), 0, (struct sockaddr*)&iDontKnow, &addr_len)

is wrong, as strlen(data) is UB, as you're trying to count the length of an uninitialized char array, which is not qualified to be a string. It invokes undefined behavior. You may want to use sizeof(data), as data is an array.

In case you're not interested in sender's info, just pass a NULL as the corresponding argument.


To add to that, for connectionless sockets (UDP), it's actually required to get the sender information. For connection oriented sockets, you have another stripped-down alternative , recv() which only takes care of receiving and storing the data.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    Thank you, I truly appreciate your help! – Jerome Carter Mar 01 '17 at 06:33
  • Which "corresponding" argument? – Jerome Carter Mar 01 '17 at 06:34
  • @JeromeCarter I meant, replace `(struct sockaddr*)&iDontKnow,` with `NULL`, that's all. – Sourav Ghosh Mar 01 '17 at 06:35
  • `Recv` is not limited to connection based sockets. It also works for datagram sockets. – Gerhardh Mar 01 '17 at 07:10
  • 1
    @Gerhardh Connect, but for TCP, you don't need to know the info for sender, that's the whole part of extablishing the connection, inn'it? – Sourav Ghosh Mar 01 '17 at 07:12
  • @SouravGhosh true, but the question is about UDP. And if the address is not needed, `recv` can be used here as well. I think this is better than using `recvfrom` and ignoring the address part. Getting the address is the only purpose of `recvfrom()`. – Gerhardh Mar 01 '17 at 07:15
  • @Gerhardh Indeed, but in that case, there's not much meaning of a code like that, right? – Sourav Ghosh Mar 01 '17 at 07:18
  • I don't question the poster's intention. If that "server" is a pure listener, it would be fine to ignore the Sender. – Gerhardh Mar 01 '17 at 07:22
  • 1
    @Gerhardh If you're the server, you have to know where to reply to, and this is the only mechanism available. – user207421 Mar 01 '17 at 08:47
  • @EJP: Again: If you only want to receive without sending responses, you don't need to know it. I would not call it a "server" then but that doesn't matter. The question is rather clear about that part. – Gerhardh Mar 01 '17 at 09:22
1

This DatagramPacket, however, only held the object in which to place the data.

And the source address and port, and the length of the data.

So, why does C's implementation of UDP receiving require that you know the sender's information?

It doesn't. It has the option to tell you the source address and port. It's a result parameter, not an input.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

You compare different functions from Java and C. In C there is also a recv() function that does not provide any address. The sole puprpose of recvfrom over recv is to get the sender's address. Normally servers reply to packets that they receive. Wihout an address that is not possible.

If you do not care about the sender of your packets, just take recv.

Or to put it the other way around: If you don't care about the sender, why did you pick the recvfrom version of recv?

I wonder what does the server server if it doesn't care about the client's addresses... But that is not related to your question.

Gerhardh
  • 11,688
  • 4
  • 17
  • 39
-2

You could do it like these,

int sockfd_recv;
struct sockaddr_in recvaddr;
bzero(&recvaddr, sizeof(recvaddr));
recvaddr.sin_family = AF_INET;
recvaddr.sin_port = htons(port_recv);
recvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(sockfd_recv, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
S.H
  • 1