cheng
cheng

Reputation: 2146

One problem with read function in c++

I am using read function to read data from a socket, but when the data is more than 4k, read function just read part of the data, for example, less than 4k. Here is the key code:

mSockFD = socket(AF_INET, SOCK_STREAM, 0);
if (connect(mSockFD, (const sockaddr*)(&mSockAdd), sizeof(mSockAdd)) < 0)
{
    cerr << "Error connecting in Crawl" << endl;
    perror("");
    return false;
}
n = write(mSockFD, httpReq.c_str(), httpReq.length());
bzero(mBuffer, BUFSIZE);
n = read(mSockFD, mBuffer, BUFSIZE);

Note than BUFSIZE is much larger than 4k. When data is just a few hundred bytes, read function works as expected.

Upvotes: 0

Views: 912

Answers (1)

selbie
selbie

Reputation: 104589

This is by design and to be expected.

The short answer to your question is you should continue calling "read" until you get all the data you expect. That is:

   int total_bytes = 0;
   int expected = BUFSIZE;
   int bytes_read;
   char *buffer = malloc(BUFSIZE+1); // +1 for null at the end
   while (total_bytes < expected)
   {
       int bytes_read = read(mSockFD, buffer+total_bytes, BUFSIZE-total_bytes);
       if (bytes_read <= 0)
           break;
       total_bytes += bytes_read;
   }
   buffer[total_bytes] = 0; // null terminate - good for debugging as a string

From my experience, one of the biggest misconceptions (resulting in bugs) that you'll receive as much data as you ask for. I've seen shipping code in real products written with the expectation that sockets work this way (and no one certain as to why it doesn't work reliably).

When the other side sends N bytes, you might get lucky and receive it all at once. But you should plan for receiving N bytes spread out across multiple recv calls. With the exception of a real network error, you'll eventually get all N bytes. Segmentation, fragmentation, TCP window size, MTU, and the socket layer's data chunking scheme are the reasons for all of this. When partial data is received, the TCP layer doesn't know about how much more is yet to come. It just passes what it has up to the app. It's up to the app to decide if it got enough.

Likewise, "send" calls can get conglomerated into the same packet together.

There may be ioctls and such that will make a socket block until all the expected data is received. But I don't know of any off hand.

Also, don't use read and write for sockets. Use recv and send.

Read this book. It will change your life with regards to sockets and TCP:

Upvotes: 6

Related Questions