views:

201

answers:

2

New to socket programming. Got a couple questions:

My program is really inconsistent with its output. Sometimes my client receives, sometimes it doesnt. I am also using the same input each time.

  1. Just need confirmation: Can the number of bytes received be less than the number of bytes sent from the server?

  2. How do I make it so that I stop receiving once I have all the bytes I need?

  3. Is there a way for a client to know how much bytes it is "going" to receive so that I may put the recv in a while loop?

Thanks for everyones time :) Doing this in C++ / non blocking if that matters at all.

+3  A: 
  1. Assuming this is TCP (not UDP), you can think of the socket as a stream of bytes. The sender can put them in in whatever way he wants, and you can get them out in whatever way you want. So the sender could write a 1k chunk in one call, and you can receive them a byte at a time if you want.

  2. There are a number of ways, but here are two fairly simple ones:

    • if the sender closes the socket after sending all of its data, the receiver will receive all the data sent, and the next call to recv will return 0, indicating that there is nothing more to receive. This is how HTTP/1.0 works.
    • You can change your protocol to send some kind of header containing the length of the data you are about to send, and then recv will know how many bytes to expect. With the Content-length header, this is how HTTP/1.1 works (well, for the most part).
  3. You can use select to tell you whether there is anything there, though it doesn't tell you how much. See question 2.

Graeme Perrow
A: 

With recv() and nonblocking the system will give you whatever number of bytes are currently available when you make the call (up to the size of the buffer which you provide).

So, if your sender for example sends 4K, this will be broken into smaller packets over the IP stream and if your call to recv() happens when just the first packet has arrived you will only get that (the rest of the data will arrive milliseconds or seconds later, depending on the latency of the network). Subsequent calls to recv() will then get none, some or all the rest of the data (depending on network timing, buffering, etc.).

Also (with non blocking IO) recv() can come back with an rc of EAGAIN which means no data is available at this point. In that case usually you use a call to select() to wait until something is available and call recv() again.

What may also help is this call:

int err, avail= 0;
err= soioctl(skt FIONREAD, (char*)&avail);

This call checks upfront how many bytes are available for read, so when you subsequently call recv() you will be served at least this number of bytes (assuming the buffer you provide to recv() is large enough).

Regarding your question on how to stop:

Usually with data over an IP stream, there is a way to tell if the message is complete. E.g. with many RFC communications (e.g. talking to a mail server or http server) commands are terminated with \n so if you receive data and there's no \n in it, you continue to read because there's supposed to be more.

In other forms the beginning of the data will have some way of telling you how much data will follow. Headers for HTTP requests have a size field or when making a connection over a SOCKS proxy, the request and return packets have defined lenghts. In such caes you can loop until you have that amount data (or until the connection fails).

But that is really a matter of defining the protocol on the stream, i.e. the sender and receiver must establish some sort of agreement how data is sent. An IMAP server reads commands up to \n and processes them, a print server might read all data until the connection is terminated (recv() failing with an rc<0) and another protocol may just first two bytes as a length field to tell how many data will follow.

Nicholaz