Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Successive calls to recvfrom() loses data?

Tags:

c

sockets

udp

I am working on a reliable file transfer program that uses UDP. (for a course in computer networking.)

My question is this - well, consider this scenario:

  1. Sender has (for example) 12 bytes of data to send. So the sender performs this call:

    sendto(fd, &buf, 12, 0, (struct sockaddr *)&cliaddr,sizeof(cliaddr));
    

    This sends the 12 bytes of data in an unreliable way. The first 4 bytes of this data happens to be a "message length" field. In this case, the first 4 bytes might have the value 0x0000000C

  2. The receiver wants to read the first 4 bytes using recvfrom(). Seeing that the segment size is 12 bytes, it wants to read the remaining 8 bytes. So the receiver might look like this:

    /* read the segment size */
    recvfrom(sockfd,&buf,4,0,(struct sockaddr *)&cliaddr,&len);
    
    /* do some arithmetic, use bzero(), etc */
    
    /* read the rest of the data */
    recvfrom(sockfd,&buf,8,0,(struct sockaddr *)&cliaddr,&len);
    

When I execute this code, I can receive the first 4 bytes without a problem. But when I try to fetch the remaining data, that data seems to be lost. In my output, I'm getting garbage - it looks like some portion of the next 12 bytes that the sender is sendto()-ing.

Is this expected behavior? That is to say, if a single recvfrom() call does not read all of the data that was sent, is it not guaranteed that that data (the remaining 8 bytes) is available to me?

It seems like the standard method of sending a segment header (including its size), followed by the payload, does not work. Does that mean that I need to send 2 separate segments - one that only contains header information, and then a 2nd segment with the payload? Or am I just using these syscalls incorrectly (or is there a flag or setsockopt() that I'm missing?)

like image 333
poundifdef Avatar asked Mar 24 '09 01:03

poundifdef


People also ask

What this function Recvfrom () does?

The recvfrom function reads incoming data on both connected and unconnected sockets and captures the address from which the data was sent. This function is typically used with connectionless sockets. The local address of the socket must be known. For server applications, this is usually done explicitly through bind.

Is Recvfrom a blocking call?

If data is not available for the socket socket, and socket is in blocking mode, the recvfrom() call blocks the caller until data arrives.

What is the return value of Recvfrom?

Returned value. If successful, recvfrom() returns the length of the message or datagram in bytes. The value 0 indicates the connection is closed.


1 Answers

From the recv(2) man page:

If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from.

This is what it looks like is happening to you.

You should have a buffer of the maximum message size and read that amount. You will read only one datagram and the length will be returned. You can then parse the length from the front of the buffer and validate it against what recvfrom(2) returned.

like image 102
camh Avatar answered Sep 27 '22 17:09

camh