Question

i developed client server program using c++,so i want to receive more than 500kb , my client message is terminated with "!" ,so i want to receive until my last byte(!) receive , this is my code it doesn't work.what is wrong with it.

do
  {
  int num = recv(*csock,  buf, bytesLeft,0);

if (num == 0)
{
  break;
}
else if (num < 0 && errno != EINTR)
{
  fprintf(stderr, "Exit %d\n", __LINE__);
  exit(1);
}
else if (num > 0)
{
  numRd += num;
  buf += num;
  bytesLeft -= num;
  fprintf(stderr, "read %d bytes - remaining = %d\n", num, bytesLeft);
}

  }

    while (bytesLeft != 0);
   fprintf(stderr, "read total of %d bytes\n", numRd);
Was it helpful?

Solution

Do you need all 1MB+ of data in one contiguous byte buffer? If so, and you stick with that protocol that has a terminating '!' and does not have a header that includes the length, then you ar stuck with memcpy() and realloc() a lot or some other buffer type like std::vector which, really just does the same thing.

If you don't need all those bytes in one string, you can store them in some other way, eg. a vector of *buffer, and so avoid copying.

OTHER TIPS

While I'm not sure exactly what your problem is because of the wording of your question, you generally can't use strcat to append raw buffers received over the network unless you know specifically they will be NULL-terminated, and even then, that's not really "safe" in the event you get an unexpected data transmission. The assumption with c-strings is that they are NULL-terminated, but a raw network buffer may not be, and using strcat will cause you to over-run the input buffer should it not be NULL-terminated. Instead of strcat, use a known fixed-size buffer of size N bytes for receiving the data into, and increment a temporary pointer through the buffer until you reach the end of the buffer or the end of the packet transmission. That way you will always read from the network up to N bytes and no more, and prevent buffer over-run situations from occuring.

For instance, you can do the following (this is not the fastest or more efficient solution because of all the copying, but it works):

unsigned char buf[10000];  //10Kb fixed-size buffer
unsigned char buffer[MAXRECV];  //temporary buffer

unsigned char* temp_buf = buf;
unsigned char* end_buf = buf + sizeof(buf);

do
{       
    iByteCount = recv(GetSocketId(), buffer,MAXRECV,0);   

    if ( iByteCount > 0 )
    {
        //make sure we're not about to go over the end of the buffer
        if (!((temp_buf + iByteCount) <= end_buf))
            break;

        fprintf(stderr, "Bytes received: %d\n",iByteCount);
        memcpy(temp_buf, buffer, iByteCount);
        temp_buf += iByteCount;
    }
    else if ( iByteCount == 0 )
    {
        if(temp_buf != buf)
        {
            //do process with received data
        }
        else
        {
            fprintf(stderr, "receive failed");
            break;
        }
    }
    else
    {
        fprintf(stderr, "recv failed: ");
        break;
    }
} while(iByteCount > 0 && temp_ptr < end_buf);  //check for end of buffer

Assuming you are using a blocking socket (which is the default mode for sockets), then recv() will block waiting for the full MAXRECV number of bytes to arrive. If the client sends less than that number of bytes, recv() will block waiting for data that does not arrive.

To work around that, you need to either:

1) call recv() with a 1-byte buffer, calling recv() until you encounter your ! byte.

2) call select() before calling recv() to detect when the socket actually has data to read, then call ioctlsocket(FIONREAD) to determine how many bytes can actually be read with recv() without blocking, then have recv() read that number of bytes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top