Avatar of OutlawZ
OutlawZ asked on

c++ recv() problem

I have a recv function inside of a thread so that i can constantly receive messages and still be able to control my GUI.
The receiving part however isn't really working the way i was hoping. Cause at a point the strings that i receive are broken appart.
So like if im expecting the string: hello_world, i get ("hel", llo", "_worl", "d") chopped up in sepperate strings.

Now my idea is to receive the messages and wait untill it encounters the newline \r\n which indicates the end of a string. When it doesn't see a newline (\r\n) yet it should paste the received string to the other strings it received before so that i still end up with the correct string.

I hope i explained it good enough of about what im trying to do, if not then please say so and ill try it again.

Would something like this work? (pseudo code)
for(;;)
{
while(recv(socket, buffer, strlen(buffer), 0))
{
    if(!strstr(buffer,"\r\n"))
    {
        completeBuffer += buffer;
    }
}
}
Editors IDEsC++Programming Languages-Other

Avatar of undefined
Last Comment
itsmeandnobodyelse

8/22/2022 - Mon
Infinity08

That looks good, except that recv returns a negative value in case of error, so your while loop should be :

        ssize_t sz = 0;
        while((sz = recv(socket, buffer, strlen(buffer), 0)) > 0) {
            /* do something with the sz received bytes - eg. add to a buffer */
        }
ravenpl

> !strstr(buffer,"\r\n")
what if they (\r & \n) comes in separate chunks?

Is it possible that two send() chunks got stuck together - then the \n can appear in the middle of the recv() input.
ASKER
OutlawZ

Yeah, thats my problem. I dont know how to check wether it is the end of the string.
I also dont know why i suddenly get strings that are split appart. Because everything works well in the beginning...

I've attached my thread code with recv(), its nothing more than a bunch of if statements

//CSockets
DWORD WINAPI Thread_SocketRecv(LPVOID lpParam)
{
 
	CSockets * csockets = CSockets::Instance2();
 
	char recvbuf[512];
	int iResult;
	char * nextBuf;
	char tmpBuf[512];
	char tmp[256];
 
	//MessageBox(NULL,"THREAD","DDD",MB_OK);
	for(;;)
	{
		iResult = recv( csockets->m_socket, recvbuf, strlen(recvbuf), 0 );
		recvbuf[iResult] = '\0';
 
		itoa(iResult,tmp,10);
		MessageBox(NULL,recvbuf,tmp,MB_OK);
		
 
		//////////////////////////////////////////////////////////////////////////////////////////
		//	BEGINSPEL
		//	@param: beginspel
		if(strstr(recvbuf,"beginspel"))
		{
			ShowWindow(hwnd_roleDialog, SW_HIDE);
			ShowWindow(hwnd_beergame, SW_SHOW);
		}
 
		else if(strstr(recvbuf,"gekozen:"))
		{
			MessageBox(NULL,"ssdas","aaa",MB_OK);
		}
 
		/////////////////////////////////////////////////////////////////////////////////////////
		//	INCOMING VALUES
		//	@param: order in:5
		else if(strstr(recvbuf,"order_in:"))
		{
			strcpy(tmpBuf,recvbuf);
			char * pch;
			pch = strtok_s(tmpBuf,":",&nextBuf);
			//MessageBox(NULL,nextBuf,"ss",MB_OK);
			SetWindowText(lblOrderIn_N,nextBuf);
		}
		//	@param: order:3 
		else if(strstr(recvbuf,"order:"))
		{
			strcpy(tmpBuf,recvbuf);
			char * pch;
			pch = strtok_s(tmpBuf,":",&nextBuf);
			//MessageBox(NULL,nextBuf,"ss",MB_OK);
			SetWindowText(lblProcessing_N,nextBuf);			
		}
		//	@param: bier in:4
		else if(strstr(recvbuf,"bier_in:"))
		{
			strcpy(tmpBuf,recvbuf);
			char * pch;
			pch = strtok_s(tmpBuf,":",&nextBuf);
			//MessageBox(NULL,nextBuf,"ss",MB_OK);
			SetWindowText(lblBeerIn_N,nextBuf);
		}
		//	@param: bier:5
		else if(strstr(recvbuf,"bier:"))
		{
			strcpy(tmpBuf,recvbuf);
			char * pch;
			pch = strtok_s(tmpBuf,":",&nextBuf);
			//MessageBox(NULL,nextBuf,"ss",MB_OK);
			SetWindowText(lblStock_N,nextBuf);
		}
		//	@param: bier uit:4
		else if(strstr(recvbuf,"bier_uit:"))
		{
			strcpy(tmpBuf,recvbuf);
			char * pch;
			pch = strtok_s(tmpBuf,":",&nextBuf);
			//MessageBox(NULL,nextBuf,"ss",MB_OK);
			SetWindowText(lblBeerSold_N,nextBuf);
		}
		//	@param: periode:32
		else if(strstr(recvbuf,"periode:"))
		{
			strcpy(tmpBuf,recvbuf);
			char * pch;
			pch = strtok_s(tmpBuf,":",&nextBuf);
			//MessageBox(NULL,nextBuf,"ss",MB_OK);
			SetWindowText(lblPeriod_N,nextBuf);
		}
 
 
		//////////////////////////////////////////////////////////////////////////////////////////
		//	BEGINSPEL
		//	@param: bezetten_rollen
		else if(strstr(recvbuf, "bezetten_rollen"))
		{
			strcpy(tmpBuf,recvbuf);
 
			char * pch;
			pch = strtok_s(tmpBuf,":",&nextBuf);
 
			char tmpRole[4];  
			for(int j=0; j<4; j++)
			{
				tmpRole[0] = *(nextBuf + j);
				tmpRole[1] = 0;
				if(j==0 && strcmp(tmpRole,"1")==0) {
					EnableWindow(cmdRole4,FALSE);
				}
				else if(j==1  && strcmp(tmpRole,"1")==0) {
					EnableWindow(cmdRole3,FALSE);
				}
				else if(j==2 && strcmp(tmpRole,"1")==0) {
					EnableWindow(cmdRole2,FALSE);
				}
				else if(j==3 && strcmp(tmpRole,"1")==0) {
					EnableWindow(cmdRole1,FALSE);
				}
				//MessageBox(NULL,tmpRole,"strtok",MB_OK);
			}
 
			//MessageBox(NULL,setRoles,"strtok",MB_OK);
		}
		
	}
	
	MessageBox(NULL,"No Thread","hhh",MB_OK);
	csockets->Handle_Of_SocketRecv = NULL;
	
    return 0; 
}

Open in new window

All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
ASKER CERTIFIED SOLUTION
itsmeandnobodyelse

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
See how we're fighting big data
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
ravenpl

> recvbuf[iResult] = '\0';
leads to SEGV(buffer overrun) if there was an error returned by recv() or recv filled whole buffer.
itsmeandnobodyelse

I personally prefer to use a select statement to test for input before reading with recv. That has the advantage that you can terminate the thread from your main thread by setting a shared flag

  // thread:
 

  while (true)
  {
         ....
         fd_set readset = { 0 };
         
         FD_SET(csockets->m_socket, &readset);
         TIMEVAL timeout = {0, 100000}; // 100 msec
         if (select(0, &readset, NULL, NULL, &timeout)  != 1)
         {
               if (global_stop) return 2;     // stop if global terminate was set
               continue;
         }
         // coming here there is some message available
         do
         {
             iResult = recv( csockets->m_socket, &recvbuf[nRead] ,
                                    sizeof(recvbuf)-  nRead, 0 );
             nRead += iResult;
         }
          while (iResult > 0 &&          // no Error
                    nRead < sizeof(recvbuf) && // no overflow
                    strlen(recvbuf) == nRead);  // no terminating zero in buffer
          ...
  }

The above will read all chunks available until either the recv returns 0 (or socket error) or until there is a binary zero char in the read buffer (with that you simply can send strlen(buffer) + 1 bytes  from the server what serves as a terminator at the receiver side (instead of \r\n).

itsmeandnobodyelse

>>>> recvbuf[iResult] = '\0';

Instead, you should set the buffer all zero at the beginning, e. g. by

   char recvbuf[512] = { 0 };  // makes all zeros

That statement must be done within the outer while loop so taht the buffer was initialized any time a new message was received.

Or, you do

   memset(recvbuf, 0, sizeof(recvbuf));

everytime you need a new buffer.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Infinity08

>> >>>> recvbuf[iResult] = '\0';

is perfectly fine, assuming that iResult is not < 0. It's faster than any of the other methods you mentioned ...
ravenpl

> recvbuf[iResult] = '\0';
but iResult may be -1 or 512 -- both leads to buffer overrun
Usually one reads 1 byte less than the size of the buffer
itsmeandnobodyelse

>>>> It's faster than any of the other methods
Yes it is 3 nanoseconds faster what really matters in case of a polling loop with a period of at least milliseconds.

As you would need to check the iResult for not being negative, the 3ns are lost as fast as won. The advantage of a char buffer initialized with all zeros is that you simply can add strings and have not to care for terminating the resulting string at all. Moreover, it is good practice to initialize *any* local variable and you will make your life happy if doing so (not listening to people who tell you can spare some time).
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
ravenpl

itsmeandnobodyelse: zeroing the buffer gives You nothing if whole buffer was read(like above example allows)
itsmeandnobodyelse

>>>> zeroing the buffer gives You nothing
If the message read isn't zero terminated (and length less than the buffer size) then the buffer keeps properly zero terminated nevertheless.

initial:
   
   buffer [ 0 0 0 0 0 0 0 0 0 0 0 ]
   
after reading hello  

   buffer [ h e l l o 0 0 0 0 0 0 ]
itsmeandnobodyelse

>>>> strlen(recvbuf) == nRead
Taht's why the above while condition would work correct.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Infinity08

>> Yes it is 3 nanoseconds faster what really matters in case of a polling loop with a period of at least milliseconds.

Sure it does. It's time that could be spent by another thread or process. What you are talking about is the same as :

        int value = 0;       // <--- initialize to 0 first
        value = 5;            // <--- and then we can set the real value
        // some code
        value = 0;            // <--- set it to 0 again
        value = 6;            // <--- before setting it to the new value

It's totally pointless. And I'm sure you don't do it for ints, so why do it for strings ?

Which part of the following code would leave room for error ?

        char buf[512] = "";
        ssize_t sz = 0;
        while ((sz = recv(sock, buf, sizeof(buf) - 1, 0)) > 0) {
            buf[sz] = '\0';
            printf("received : %s\n", buf);
        }
        if (sz < 0) {
            // handle error
        }

Why would you have to waste processor cycles setting memory to 0 that will be overwritten with other values immediately after ? Or why would you have to waste processor cycles setting up (and initializing) a new buffer for every iteration ?


>> Moreover, it is good practice to initialize *any* local variable and you will make your life happy if doing so

As you can see, all variables ARE initialized. I am not using any memsets though, and I am re-using the buffer for every iteration.
itsmeandnobodyelse

>>>> And I'm sure you don't do it for ints, so why do it for strings ?
You are wrong. I mostly do that like this and it prevents me from a lot of errors.

Note, as I am (mostly) a C++ programmer I don't necessarily define new local variables at top of my function or block but when I need them. Therefore duplicate initializations were the exception but will occur:

    int i = 0;

    ....

    for (i = 0; i < n; ++i)

That occurs very often in my programs and it allows me to use the i in any above block and it wouldn't matter if I forget to initialize

>>>> char buf[512] = "";
That doesn't make the buffer all zeros but is equivalent to
   
      buf[0] = '\0';

>>>> Why would you have to waste processor cycles
We have a different understanding of waste.

An initialization isn't a waste but an investion that reduces errors and helps when debugging.


>>>        while ((sz = recv(sock, buf, sizeof(buf) - 1, 0)) > 0) {
>>>            buf[sz] = '\0';

The loop will only work properly if there is no split of the message. otherwise the second chunk will overwrite the first.

you need

    buf[sz] = '\0';

within the loop what is an indexed array access. I don't think that your code is faster by doing this. If you look at the buffer in the debugger you will see all garbage the first time as it isn't initialized. Same applies if the read returns with error ort 0 bytes read.
Infinity08

>> >>>> char buf[512] = "";
>> That doesn't make the buffer all zeros but is equivalent to
>>   
>>       buf[0] = '\0';

I know ;) So, what's your point ?


>> An initialization isn't a waste but an investion that reduces errors and helps when debugging.

As I asked : how does your approach avoid more errors than the code I posted ?


>> The loop will only work properly if there is no split of the message. otherwise the second chunk will overwrite the first.

Doesn't matter ... I've already processed the first chunk. Note that the printf can be anything else - it could be a copy into a different buffer for example. Either way, that's not the point I was making ...


>> I don't think that your code is faster by doing this.

So you claim that setting all 512 bytes to 0 is faster than setting 1 byte to 0 ?


>> If you look at the buffer in the debugger you will see all garbage the first time as it isn't initialized. Same applies if the read returns with error ort 0 bytes read.

That doesn't matter, since that garbage will never be read anywhere. Name one case where garbage would be read using the code I posted.
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
ASKER
OutlawZ

I changed the strlen to sizeof and guess what, it seemed t obe working :D
I really thank you all for all of the information you gave me, it was really interesting to read and real helpful for me :)
itsmeandnobodyelse

>>>> I know ;) So, what's your point ?
I know that you know ;-)   My point is that I prefer to init all bytes of a buffer while you only set the first character to zero. And that isn't equivalent.

Look at

   strlen(buffer+1)

versus

   strlen(buffer)+1

The first is a often seen error when people try to provide a buffer for making a copy. In case buffer is a full initialized all zero buffer the first is always two bytes less than what is correct. If the buffer isn't initialized and made empty as you did in your sample, the strlen(buffer + 1) may have arbitrary values. Actually, the first would have been detected very fast as in case of an empty buffer the result is 0 and not at least 1 as expected. With the uninitialized buffer - actually it was a real life bug I found some month ago - we had no crash but sometimes some strange garbage at the screen which hardly could be explained.

>>>> As I asked : how does your approach avoid more errors than the code I posted ?
You should see that your code was not your initial post (where you actuall said that the autor's code using strlen for an uninitialized buffer "looks good") but an answer to my recommendation to initializing all variables. You initialized all variables as well beside that the buffer was initialized only in the very first byte. I think I don't have to tell you that such kind of initialization only works with simple single-byte C strings. For any binary data or even UNICODE your approach isn't valid. And it isn't safe against pointer arithmetics, requires additional termination each time you copy another portion of string.

>>>> Name one case where garbage would be read using the code I posted.
After the recv and before setting the zero character you'll see garbage in the debugger.

The point is that you always have to care whether one of your operations was pointing into the uninitialized part and you have to do something against it. I don't have to care as I only work with well-defined data.

>>>> So you claim that setting all 512 bytes to 0 is faster than setting 1 byte to 0 ?
Actually I didn't. But you can't proof the contrary as all we discuss is below any measurable time. You would need maybe a million of repetitions what hardly is real to show some advantage of your approach if at all and perhaps some compiler will optimize your code and another my code so that actually no processor cycle was wasted ...

>>>> Doesn't matter ... I've already processed the first chunk.
Doesn't matter? How will you know? You say a repeated assignment of an array element in a loop cost's much less than a one-time initialization of a 512 byte buffer. Then you say you were regarding the first chunk only. What about omitting the loop in your solution at all? It surely will run faster then.
Infinity08

>> I know that you know ;-)   My point is that I prefer to init all bytes of a buffer while you only set the first character to zero. And that isn't equivalent.

No, but it's sufficient.


>> actually it was a real life bug I found some month ago

Interesting ... One point for you ;)


>> (where you actuall said that the autor's code using strlen for an uninitialized buffer "looks good")

Yes. I was a bit too fast there :) But you fixed my mistake. That's why I'm glad I've got backup lol


>> You initialized all variables as well beside that the buffer was initialized only in the very first byte.

I always initialize variables. I just don't overwrite an entire buffer with zero's when it's not needed. In this case it's not, since the zero's will be overwritten by the recv anyway, and a zero will be appended in the correct location. The end result is still correct.
Note that initializing a string (ie. setting it to a 0-length string) is not the same as zero-ing a buffer.


>> For any binary data or even UNICODE your approach isn't valid.

Why not ? The data in the buffer is overwritten, and a length is returned which tells you how many bytes in the buffer are valid data.
Zero-ing the buffer will not make a difference anyway in case of binary data, since a zero byte is a valid data byte, so you can't detect the end of the data using the zero bytes as you can with strings.


>> After the recv and before setting the zero character you'll see garbage in the debugger.

Euhm ... name one case at runtime ...
Even when initializing the buffer to all zero's, the debugger will show garbage content before it's initialized, so ... that's no different.
The point is that the size value says how many bytes in the buffer are valid. The rest are garbage and should not be used.


>> I don't have to care as I only work with well-defined data.

There's no difference. You have to care too, since you can't use indexes smaller than 0 or greater than 511. You can also not read data past the end of the string, because that well give you incorrect data (a zero length string, yes, but incorrect).

It's very simple really, the buffer has a size of 512 bytes, so you can use indexes 0 through 511 to access the buffer. The USED part of the buffer is sz bytes, so you can use indexes 0 through (sz-1) to access the data. That's not complicated, nor does it require more work than your method.


>> But you can't proof the contrary as all we discuss is below any measurable time.

Find me a (common) CPU that can set 512 bytes to 0 in the same amount of time as it can set one byte to 0, and I'll gladly admit defeat.

Btw, your point that it's below measurable time is invalid, since everything we do when writing programs is below measurable time. Adding two values ? Too fast for the human brain (a few clock ticks). Does that mean you shouldn't care about it ? How fast would Apache (for example) be if the writers didn't care about such things because it's not measurable anyway ?


>> You say a repeated assignment of an array element in a loop cost's much less than a one-time initialization of a 512 byte buffer.

When did I say that ? Your equivalent to my code would be (correct me if I'm wrong) :

        char buf[512] = { 0 };
        ssize_t sz = 0;
        while ((sz = recv(sock, buf, sizeof(buf) - 1, 0)) > 0) {
            printf("received : %s\n", buf);
            memset(buf, 0, sz);
        }
        if (sz < 0) {
            // handle error
        }

So, a one-time zero-ing of the buffer on initialization, and zero-ing the buffer on every iteration.
I'm saying that zero-ing the buffer on every iteration will take (a lot) more time than simply setting one zero byte at the end of the valid data on each iteration.


>> What about omitting the loop in your solution at all? It surely will run faster then.

The loop is there because we might have to receive more than 512 bytes ... I think you're misunderstanding me ...

Compare both code samples I posted. The first is the way I would do it ... The second is the way you would do it (again : correct me if I'm wrong). Compare them, and tell me which one requires less clock cycles (and I'm not talking about I/O wait, because that time can be spent by other threads/processes).



Anyway, we've beaten this horse to death now ... We've both made our point. I'm ready to let this rest if you want.
I'm also happy to continue discussing this if you prefer ;) I'm just not sure we'd get anywhere lol.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
itsmeandnobodyelse

>>>> Your equivalent to my code would be (correct me if I'm wrong) :
Of course the second memset makes no sense. The initialization of the buffer above the loop is the only I would need in the sample as any concatenation (of course within buffer boundaries) automaticaly is terminated properly because of the initial zeroes. I don't know whether using always the same buffer and memsetting it or always creating a new initialized buffer is the faster method. I can think of a compiler optimization which was able to make the same machine code for both approaches. Nevertheless my main concern isn't the performance as I mainly make application and dialog software. My concern is to reduce all potential errors to an absolute minimum. And the main source of errors is if you do sometimes this way, and sometimes that way. If you need to look at code written by me, you can be 99.99 % sure that any variable is initialized, that the initialization is a zero-based initialization (even if some variable later needs a different start value), and that all arrays are fully initialized as well. There is really no room for alternatives, and I never have had a reason to overthink these kind of self-made programming rules.

>>>> Zero-ing the buffer will not make a difference anyway in case of binary data, since a zero byte is a valid data byte
The argument is wrong and you would know better if you ever had written a DBMS yourself. Of course any bucket (record) in a presized dbms file is initialized with zeros, even if it is only half full and even if the bytes filled is included in some fix part of each bucket. Any other approach wouldn't make much difference for a program but would be a crazy (if not absurd) doing as of course human beings looking at such a record are highly dependent on a  proper initialization.

>>>> Find me a (common) CPU that can set 512 bytes to 0 in the same amount of time as it can set one byte to 0
Not the assignment is the critical part but the indexed access. It cannot be optimized as the increments have a variable size. I don't know much of assembler but initializing a 512 byte buffer most likely wasn't done by means of a loop but can be done with very few machine operations (if not with one). On the other hand a statement like

    buffer[sz] = '\0';

can be optimized to

    *(buffer+sz) &= 0;

but as the operands are bytes it needs at least some byte operations which are not known as to be very fast. I really don't think that it can be made with less machine operations than a first-time initialization of a 512 byte buffer but you most probably know better. But again, I wouldn't care if it does cause the knowledge of always operating on fully initialized variables is very worthful for me.

In the sample code above, the loop - most likely - would run only one cycle (after the sizing bug was fixed). But as told, I always make the initializations same way, no matter if currently need it or not. That way I can't 'forget' it or oversee it when the purpose of a buffer changes later. And forgetting things is going to become a problem with getting older ;-)


>>>> The loop is there because we might have to receive more than 512 bytes
No, I would say the loop is there because a message could have been split into two or more chunks. In that case you have to make the parts a complete message ... and hardly can process the parts solely as you suggested above (that is why I didn't accept your sample which was ignoring the issue)

If you write both server and client you most probably know the maximum message size and can choose an appropriately sized buffer to receive (simply take the double-size of whatever could come). Even a foreign server normally wouldn't operate with arbitrary message lengths but has some - more or less well-known - maximum message size. All other things may happen as well - here in EE more than in real life - but in very most cases you will have to find it out once  and later it won't change its behavior. That doesn't mean to not checking for buffer overflow but most likely these code sequences never actually were needed. If the overflow is a rare 'exception' you may even decide to not handling it but exit with error. That is very easy when calling recv as it would return with socket error in case you provide a zero length buffer after some loop cycles.  

From my experiences you must not expect that small messages were split into chunks when using TCP/IP. I actually ran a server for seven months without pause and there was not one single buffer break (though some clients had hang-ups or even were crashing) in a sequence of millions of requests (i know as I had a logging there).  Because of that experience, I would say we even could omit the loop, but of course things may be different between operation systems, and people and software.  

Infinity08

>> The initialization of the buffer above the loop is the only I would need in the sample as any concatenation (of course within buffer boundaries) automaticaly is terminated properly because of the initial zeroes.

The idea of the sample code was that you are not able to concatenate - you are receiving a max. of 511 bytes in each iteration, for a total of maybe a million bytes, who knows. So, with your approach, you'd need to constantly zero the buffer.


>> Of course any bucket (record) in a presized dbms file is initialized with zeros,

I'm not sure what that has to do with a network transfer buffer (in memory) ... You're talking about a long-term storage method in files, which is the complete opposite of a temporary buffering method in memory.


>>     buffer[sz] = '\0';
>> 
>> can be optimized to
>> 
>>     *(buffer+sz) &= 0;

It's the compiler's job to decide which way is faster. Indexed array access is common enough to be a very fast operation, and it is on all common systems I know.


>> In the sample code above, the loop - most likely - would run only one cycle (after the sizing bug was fixed).

I'm not sure what you mean by the "sizing bug", but the loop is intended to iterate more than once since it needs to be able to receive more than 511 bytes.


>> No, I would say the loop is there because a message could have been split into two or more chunks.

I created the example, so I get to decide what it was intended for ;) Imagine that it WAS meant for receiving more than 511 bytes, and then read over my arguments again. Maybe they will make more sense, maybe not ... heh.



>> In that case you have to make the parts a complete message ... and hardly can process the parts solely as you suggested above (that is why I didn't accept your sample which was ignoring the issue)

The buffer is a transfer buffer, not necessarily a processing buffer. Its only intent is to receive data in blocks of 511 bytes (because maybe that's the most optimal or easiest way).
Often, data can already be processed, even if a message is not completely received yet. If that's not possible, then code needs to be added to handle that case differently.
I'm not ignoring it - it's just not relevant for our discussion.

Btw, who says that the code is only receiving one message ? Again, that doesn't matter. The point is that if you are re-using the same buffer, you'll need to zero that buffer EACH time, and that's potentially a lot of times ...


>> If you write both server and client you most probably know the maximum message size

It might be more common than you think that neither knows the maximum size. Take HTTP as a simple every-day example : I've seen web pages that amount to MB's, instead of just a few kB's. This page we're writing on atm for example is already 168 kB !!
You might notice that your browser loads web pages in chunks (incrementally) ... This is the reason ;)
itsmeandnobodyelse

>>> If that's not possible, then code needs to be added to handle that case differently
One last remark (to that dead, buried, and maybe wrotten horse...)

The initial question was because the author got his message in chunks rather than with one read. My conclusion from that was that the main purpose of the function was to build a full message out of possible incomplete transfers. As far as I see there is no hint that the function should be able to receive messages longer than the buffer size but only expects short messages perhaps from some kind of chat ("so that i can constantly receive messages and still be able to control my GUI"). If I am right, my suggestion is to take a sufficiently big buffer, big enough for any potential message and use the recv loop to complete one single message as I showed above. If for any reason the buffer turns out to be too short nevertheless, the function would return with error ("message exceeds buffer size") which can be achieved wih the normal handling of socket errors after recv.  
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23