2

I'm attempting to write a rudimentary file server that takes a filename from a client and responds by sending the data over TCP to the client. I have a working client and server application for the most part but I'm observing some odd behavior, consider the following

    while ((num_read = read (file_fd, file_buffer, sizeof (file_buffer))) > 0)
    {
        if (num_read != write (conn_fd, article_buffer, num_read))
        {
            perror ("write");
            goto out;
        }
    }
    out:
           close(file_fd); close(sub_fd);

file_fd is a file descriptor to the file being sent over the network, conn_fd is a file descriptor to a connect()ed TCP socket.

This seems to work for small files, but when my files get larger(megabyte+) it seems that some non-consistent amount of data at the end of the file will fail to transfer.

I suspected the immediate close() statements after write might have something to do with it so I tried a 1 second sleep() before both close() statements and my client successfully received all of the data.

Is there any better way to handle this than doing a sleep() on the server side?

user2278457
  • 315
  • 2
  • 9

1 Answers1

0

A successful "write" on a socket does not mean the data has been successfully sent to the peer.

If you are on a unix deriviative, you can perform a "man 7 socket" and examine SO_LINGER" as a potential solution.

edit: Due to EJP's comment (thank you), I reread what Stevens has to say about the subject in "Unix Network Programming" of ensured delivery of all data to a peer. He says the following (in Volume 1 of Second edition, page 189):

... we see that when we close our end of the connection, depending on the function called (close or shutdown) and whether he SO_LINGER socket option is set, the return can occur at three differrent times.

  1. close returns immediately, without waiting at all (the defaults; Figure 7.6)
  2. close lingers until the ACK of our FIN is received (Figure 7.7), or
  3. shutdown followed by a read waits until we receive the peer's FIN (Figure 7.8)

His figures, and his commentary, indicate other than "application level acknowledgement", the combination of shutdown(), followed by a read() waiting for a zero return code (i.e. notification that the socket has been closed), is the only way to ensure the client application has received the data.

If, however, it is only important that the data has been successfully delivered (and acknowledged) the the peer's computer, then SO_LINGER would be sufficient.

TonyB
  • 927
  • 6
  • 13
  • SO_LINGER doesn't really solve this problem, it just makes it possible to *detect* when the final pending data can't be written. In this case the problem is almost certainly at the receiving end. – user207421 Oct 09 '14 at 07:01