0

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);
Mr.Cool
  • 1,525
  • 10
  • 32
  • 51
  • 3
    1) Don't use strcat() strlen() on non NUL-terminated buffers. 2) don't mix C and C++ 3) Diagnostic output should go to stderr, not stdout, adding a \n sometimes helps. 4) thank you. – wildplasser Apr 04 '12 at 12:35
  • Is your socket _blocking_ or _non-blocking_? By default, all sockets are blocking, and that means if there is no data receive then the call to `recv` will _block_ while waiting for more data to arrive. – Some programmer dude Apr 04 '12 at 12:36
  • rule of thumb: read the manuals for all commands you are using. – hochl Apr 04 '12 at 12:46
  • 1
    So what's the question? What problems are you having? WHat output are you getting? Please edit your question and provide more details. – Gray Apr 04 '12 at 15:56

3 Answers3

6

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
Jason
  • 31,834
  • 7
  • 59
  • 78
  • if i sent 10 kb data means, but icant receive the entire data at one receive ,because the 10kb data is divided into 6 packet so i want to call recv() 6 times then only i will get entire data,that's y i use strcat – Mr.Cool Apr 04 '12 at 12:38
  • 1
    @Mr.Cool - yes, we know why you want to concatenate the buffer data, but Jason etc. are saying, (correctly), that strcat() will not do the job! – Martin James Apr 04 '12 at 12:41
  • @Martin James -then how can i get entire data ? – Mr.Cool Apr 04 '12 at 12:44
  • @Jason actually my data size upto 10 kb my msg format is"EXT#my data#0!"here "!" is my message terminated i want to receive upto "!" but when i sent the message server can't receive entire data ,it may be size of my data or fault in my code – Mr.Cool Apr 04 '12 at 12:51
  • What are the types of buf, buffer etc? Where is space being allocated? The only sure thing I can see is that, if you need all the mesage in contiguous bytes, you are coin to end up copying it, perhaps with memcpy() - something that does not care about null bytes. – Martin James Apr 04 '12 at 12:51
  • Are you in a position to change the protocol or nest your own? Could the client send the length first, perhaps in fixed-field ASCII: 'ETX001000000#one million bytes of my data#0!' You would then know how much space to allocate for buf and could copy it in as it is received without continual reallocations. – Martin James Apr 04 '12 at 12:56
  • @ Martin James it is possible to receive the data until my last character arrive ,in another application(in c# i use Readbyte() it receive the data until last character "!" but c++ it dsn;t work )in c++ i only use recv(), – Mr.Cool Apr 04 '12 at 13:14
  • some time my data size is upto 500kb – Mr.Cool Apr 04 '12 at 13:17
  • @Mr.Cool: You're going to have to dynamically allocate the buffer then. You can use either `realloc` to increase the size of the buffer, you can do something like an `iovec` data-structure, which is basically an array of pointers to buffers, or you can use a linked-list data-structure, appending each node which contains a read buffer to the end of the list. – Jason Apr 04 '12 at 13:38
  • @Mr.Cool: I guess in C# you receive each separate byte and check whether it's '!'. You can do this too in C++ (when performance is not an issue) by setting MAXRECV to 1, but you still need to check for '!', which is not done here. If performance is an issue, make MAXRECV higher and use memchr to check for '!', but you still have some issues to handle (e.g. buffer-overflow, str-functions,...) – stefaanv Apr 04 '12 at 14:47
1

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.

Martin James
  • 24,453
  • 3
  • 36
  • 60
1

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770