Skip to content
Advertisement

Printf makes program work in C, htonl and ntohl not working?

This is for a Linux system, in C. It involves network programming. It is for a file transfer program.

I’ve been having this problem where this piece of code works unpredictably. It either is completely successful, or the while loop in the client never ends. I discovered that this is because the fileLength variable would sometimes be a huge (negative or positive) value, which I thought was attributed to making some mistake with ntohl. When I put in a print statement, it seemed to work perfectly, without error.

Here is the client code:

JavaScript

This is the server code:

JavaScript

Note: I’ve simplified the code a bit, to make it clearer I hope. Anything beginning with //… represents a bunch of code

Advertisement

Answer

You seem to be assuming that each send() will either transfer the full number of bytes specified or will error out, and that each one will will pair perfectly with a recv() on the other side, such that the recv() receives exactly the number of bytes sent by the send() (or error out), no more and no less. Those are not safe assumptions.

You don’t show the code by which you set up the network connection. If you’re using a datagram-based protocol (i.e. UDP) then you’re more likely to get the send/receive boundary matching you expect, but you need to account for the possibility that packets will be lost or corrupted. If you’re using a stream-based protocol (i.e. TCP) then you don’t have to be too concerned with data loss or corruption, but you have no reason at all to expect boundary-matching behavior.

You need at least three things:

  • An application-level protocol on top of the network-layer. You’ve got parts of that already, such as in how you transfer the file length first to advise the client about much content to expect, but you need to do similar for all data transferred that are not of pre-determined, fixed length. Alternatively, invent another means to communicate data boundaries.

  • Every send() / write() that aims to transfer more than one byte must be performed in a loop to accommodate transfers being broken into multiple pieces. The return value tells you how many of the requested bytes were transferred (or at least how many were handed off to the network stack), and if that’s fewer than requested you must loop back to try to transfer the rest.

  • Every recv() / read() that aims to transfer more than one byte must be performed in a loop to accommodate transfers being broken into multiple pieces. I recommend structuring that along the same lines as described for send(), but you also have the option of receiving data until you see a pre-arranged delimiter. The delimiter-based approach is more complicated, however, because it requires additional buffering on the receiving side.

Without those measures, your server and client can easily get out of sync. Among the possible results of that are that the client interprets part of the file name or part of the file content as the file length.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement