Search code examples
csocketswhile-loopudprecvfrom

detect when to stop receiving data ( recfrom() ) from server when using UDP for file tranfer (sockets API)


I am trying to implement a UDP version for file transfer ( for learning purposes, i do not care about reliability :) ).

Currently in the TCP version, I have the following code on the server side :

while (1)
{
    /* read file in chunks of 256 bytes */
    unsigned char buff[256] = {0};
    int nread = fread(buff, 1, 256, fp);
    /* If read was success, send data. */
    if (nread > 0)
    {
        printf("Sending \n");
        send(connfd, buff, nread, 0);
    }
    if (nread < 256)
    {
        if (feof(fp))
            printf("End of file\n");
        if (ferror(fp))
            printf("Error reading\n");
        break;
    }
}
close(connfd); // client-specific socket
close(serverfd); // listening socket

and on the client side of the TCP version, I have this

while ((bytesReceived = recv(sockfd, recvBuff, sizeof(recvBuff), 0)) > 0) 
{
    fwrite(recvBuff, 1, bytesReceived, fp); 
}

This code runs perfectly. The reason I believe that the while loop on the client side terminates is that recv() returns 0 when the server process shuts down orderly on calling close(serverfd). On removing 'close(serverfd)', the client process hangs which I think is due to recv() being blocking by default.

Now coming to my UDP implementation:

Server side:

char send_buf[256];
while((bytes_read = fread(send_buf, sizeof(char), 256, fp))>0)
{
    res = sendto(server_socket, send_buf, sizeof(send_buf), 0, (struct sockaddr*)&si_server, sizeof(si_server));
    if(res == -1) die("send failed");
}
if(!feof(fp)) die("error in reading file");

close(server_socket);

Client side:

while((bytes_rcvd = recvfrom(client_socket, recv_buf, sizeof(recv_buf), 0, (struct sockaddr*)&si_server, &si_server_len)) > 0)
{
    fwrite(recv_buf, 1, bytes_rcvd, fp);
}

close(client_socket);

In this UDP version, the client side always hangs. I am not able to figure out, what would be the termination condition for the while loop in the client side. Apparently for UDP, upon closing the server socket, recfrom() does not return 0 (unlike for TCP). How do I figure out when to stop calling recvfrom() ?

Thanks!!


Solution

  • There are three approaches to size management with UDP:

    • Give each message a size, and prefix your submissions with such size - you will keep reading until you have read size bytes.
    • Send the whole message in the single UDP packet - quite feasible if message size is less than MTU size (best avoided for messages longer than MTU and impossible for messages longer than max unsigned short)
    • Introduce a terminator in the message, which delineates end of message. Often impractical.

    In your case, option 2 seems feasible. Your message size is 256 bytes - well within standard MTU - and could be send in a single go. You will have to first assemble the message in the buffer, and than send the whole buffer.

    Please note, your loop for data reading from the file seems broken to me. You can only read less bytes than requested if there is less bytes in the file, but in this case your eof check will return true. I would be very surprised to learn that you have observed your file reading loop to execute more than once.