C Board  

Go Back   C Board > General Programming Boards > Networking/Device Communication

Reply
 
LinkBack Thread Tools Display Modes
Old 05-07-2009, 11:00 PM   #1
Registered User
 
Join Date: Dec 2008
Posts: 183
info on memset and recv

Hello I just downloaded few sources in networking in most of them they do
Code:
memset(buffer, 0, sizeof(buffer));
and after that recv the buffer
I had a problem before in a program but when i added memset to it it worked good i wanna
why in most cases they do memset isnt buffer alrdy doesnt have anything inside it why would i memset it ?
lolguy is offline   Reply With Quote
Old 05-07-2009, 11:05 PM   #2
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
- Lazyness
- Hide bugs
- "voodoo" programming

In short, it's a waste of time if your use of recv() is correct.
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 05-08-2009, 12:04 AM   #3
CSharpener
 
vart's Avatar
 
Join Date: Oct 2006
Posts: 5,242
in other words - it is workaround to ensure the received buffer is nul-terminated string when the usage of recv() is incorrect.

So instead of using this CPU consuming workaround - better way is to fix the usage of recv()
__________________
If I have eight hours for cutting wood, I spend six sharpening my axe.
vart is offline   Reply With Quote
Old 05-08-2009, 07:21 AM   #4
subminimalist
 
MK27's Avatar
 
Join Date: Jul 2008
Location: NYC
Posts: 3,944
Quote:
Originally Posted by lolguy View Post
and after that recv the buffer
why would i memset it ?
The reason for this is that recv DOES NOT ADD A NULL TERMINATOR. However, if there is a '\0' at the end of the string read by recieve -- which would be "proper" -- then it will be included, presuming the buffer is big enough.

However, sometimes with networking you cannot be held responsible for the string you are receiving, so you may want to make sure it is null terminated if you need it to be. Also, you are not guaranteed to "recv" the entire string, which means if you "properly" presume it will be there, it may not. Usually the answer to this is to keep trying, but it is also a good idea to make sure in the end, by adding a null terminator to the end after the recv call.

memset'ing the buffer first will accomplish the same thing, and although it would not be my choice of methods, I have to say that vart and Salem are both way, way, way off base when they claim the point is to cover a bug or because the use of recv is "incorrect". There is nothing "incorrect", "voodooish", or even "hackish" about the use of memset here and the OP is correct in observing that it is commonly done. It is NOT a sign of bad programming, it's a programming preference.

My preference would be to add or at least check for the null terminator after the recv, which seems more optimal.
__________________

Accuracy and integrity mean nothing if you don't make it past the censors...PYTHAGORAS
MK27 is offline   Reply With Quote
Old 05-08-2009, 09:37 AM   #5
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
> I have to say that vart and Salem are both way, way, way off base when they claim the point is to cover a bug or because the use of recv is "incorrect".

Example

Code:
memset( buff, 0, sizeof buff )
recv( sock, buff, sizeof buff, 0 );
If recv() actually FILLS the buffer, then two things
a) the memset was a complete and utter waste of time,
b) the resulting buffer STILL DOES NOT have a \0, nor does it have room for one either.

In other words, a total loss.

Consider
Code:
// drop the -1 if you're not interested in making a string
n = recv( sock, buff, sizeof buff - 1, 0 );  
if ( n > 0 ) {
  buff[n] = '\0';  // if you really want a \0 string
  // do stuff with 'n' bytes
}
Done this way, the need for memset hokus-pokus vanishes, the buffer is correctly \0 terminated in a single instruction (or two, but certainly much more efficiently than memset), if that is what you want to do.
In any event, the real size of the received data is available to make sure you can do the right thing.


> My preference would be to add or at least check for the null terminator after the recv, which seems more optimal.
Who said that you were going to get a \0 from recv()
Who said that you were going to receive it in a timely manner, even if it was sent?

It's quite simple. Use the return result of the function properly, and you're not going to go wrong.
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 05-08-2009, 10:19 AM   #6
subminimalist
 
MK27's Avatar
 
Join Date: Jul 2008
Location: NYC
Posts: 3,944
Quote:
Originally Posted by Salem View Post
Use the return result of the function properly, and you're not going to go wrong.
Sure, and that's the byte where I would place the zero.

However, I still can't say that it's wrong to use memset there. You just made up a ridiculous example:
Code:
memset( buff, 0, sizeof buff )
recv( sock, buff, sizeof buff, 0 );
The error here IS NOT MEMSET, it's that the recv parameter should be "sizeof buff" minus 1.

Then you reinterate two points that I made explicitly, as if I had not accounted for them, which I did -- explicitly:
Quote:
Originally Posted by Salem
Who said that you were going to get a \0 from recv()
Who said that you were going to receive it in a timely manner, even if it was sent?
Quote:
Originally Posted by mk27
sometimes with networking you cannot be held responsible for the string you are receiving, so you may want to make sure it is null terminated if you need it to be. Also, you are not guaranteed to "recv" the entire string, which means if you "properly" presume it will be there, it may not.
With your level of experience, etc, I don't think you have any excuses for failing to read properly, so either do so or stop overtly trying to confuse the OP with your tish.
__________________

Accuracy and integrity mean nothing if you don't make it past the censors...PYTHAGORAS
MK27 is offline   Reply With Quote
Old 05-08-2009, 10:39 AM   #7
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
> The error here IS NOT MEMSET, it's that the recv parameter should be "sizeof buff" minus 1.
Thanks for pointing out that memset() is useless in this context.

As for "made up" examples, you've no idea how many times I've seen people forget the -1, then wonder WTF is going on.
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 05-08-2009, 04:33 PM   #8
+++ OK NO CARRIER
 
quzah's Avatar
 
Join Date: Oct 2001
Posts: 10,258
Quote:
Originally Posted by MK27 View Post
The error here IS NOT MEMSET, it's that the recv parameter should be "sizeof buff" minus 1.
It's not an error to do this:
Code:
#define THISROCKS { \
    size_t thisrocks = 1; \
    while( thisrocks++ ); \
    }

...
THISROCKS
// drop the -1 if you're not interested in making a string
n = recv( sock, buff, sizeof buff - 1, 0 );  
THISROCKS
if ( n > 0 ) {
THISROCKS
  buff[n] = '\0';  // if you really want a \0 string
  // do stuff with 'n' bytes
}
But it doesn't make it good thing to do either.


Quzah.
__________________
Hundreds of thousands of dipshits can't be wrong.


Are you up for the suck?
quzah is offline   Reply With Quote
Old 05-08-2009, 07:33 PM   #9
Registered User
 
Join Date: Dec 2008
Posts: 183
also today i Noticed while coding that send doesnt send Null terminator with send itself you have to add strlen(buffer)+1 maybe thats the case with memset
lolguy is offline   Reply With Quote
Old 05-08-2009, 09:02 PM   #10
+++ OK NO CARRIER
 
quzah's Avatar
 
Join Date: Oct 2001
Posts: 10,258
Memset will set however many bytes you tell it to. It's not its fault you passed it the wrong number of bytes. The same thing goes for recv. Hell, all functions for that matter. It's not really their job to double check everything you pass it to make sure it is what you thought it was. It's nice to provide in-function error checking, but really, there's no way for you to know that the buffer you've been passed is supposed to be only 99 bytes instead of 100. To think it's the function's fault is just silly.

Quzah.
__________________
Hundreds of thousands of dipshits can't be wrong.


Are you up for the suck?
quzah is offline   Reply With Quote
Old 05-08-2009, 09:08 PM   #11
Registered User
 
Join Date: Dec 2008
Posts: 183
well i m not saying its the function fault I was just curious why memset when i pass to buffer it fixes it now i now that i Should also add +1 for strlen to add the Null character to the string
lolguy is offline   Reply With Quote
Old 05-09-2009, 01:33 AM   #12
+++ OK NO CARRIER
 
quzah's Avatar
 
Join Date: Oct 2001
Posts: 10,258
Because...

man strlen
Quote:
RETURN VALUES
The strlen() function returns the number of characters that precede the
terminating NUL character.
If you want to keep it a string, you need to add a null character. Without it, it's not a string.


Quzah.
__________________
Hundreds of thousands of dipshits can't be wrong.


Are you up for the suck?
quzah is offline   Reply With Quote
Old 05-09-2009, 01:56 AM   #13
and the hat of vanishing
 
Salem's Avatar
 
Join Date: Aug 2001
Location: The edge of the known universe
Posts: 21,214
> now i now that i Should also add +1 for strlen to add the Null character to the string
But you're still wrong.

Just because you managed to send(*) 12 bytes of "hello world\0" doesn't mean that the recv call will get all 12 bytes in a single call.

It's perfectly allowed to receive "hell" on the first call and then "o world\0" on the second call.
Sadly for you, your mis-handling of the code drags it through the brier patch and it is now slowly bleeding to death.

TCP is a stream protocol, which means the only guarantee you have is the order of bytes. The number of bytes sent in a single send() call has NOTHING to do with the number of bytes in some subsequent recv() call. So your thinking of "I've sent a \0, why isn't it working" is just another symptom of the problem.

The Eight Fallacies of Distributed Computing
No doubt your early "success" sending to yourself @127.0.0.1 might lead you to think otherwise, but you only figure out what latency means when you travel .uk to .nz


memset() here, send a \0 there - you seem to be doing EVERYTHING to try and make sure there is a \0 there for you to use, yet all the while you continue to miss the target.
USE the return result of recv() and stop messing about.
It's the only thing which can and will work. All this voodoo will fail you at some point.


(*) I might also add that send() doesn't guarantee to send the whole message in a single call either.
__________________
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
Up to 8Mb PlusNet broadband from only £5.99 a month!
Salem is offline   Reply With Quote
Old 11-07-2009, 08:52 AM   #14
Registered User
 
Join Date: Dec 2007
Location: France
Posts: 396
I dont really understand why we should add +1 to send.

If you send for example "hello" which is 5 bytes + 1 for the '\0'.

It will send "hello" + 1 byte which will be a garbage char because send() doesnt put '\0' at the end either.

Code:
     send(mySocket, "hello",  6, 0);
So on the other side you will get (after making sure you got it all) "hello" + 1 garbage char.

So now if you do

Code:
buffer[i] = '\0';
you will put your '0' after the garbage char because you have recieved 6 bytes.

So wouldnt it be better to send only strlen(buffer) without the +1 ?
__________________
Using Code::Blocks,MingW with Windows.

Last edited by Ducky; 11-08-2009 at 07:17 AM.
Ducky is offline   Reply With Quote
Old 11-12-2009, 01:31 AM   #15
int x = *((int *) NULL);
 
Cactus_Hugger's Avatar
 
Join Date: Jul 2003
Location: Banks of the River Styx
Posts: 891
Quote:
It will send "hello" + 1 byte which will be a garbage char because send() doesnt put '\0' at the end either.
Nope. "hello" is a length 6 character array, containing
Code:
{'h', 'e', 'l', 'l', 'o', '\0'}
strlen("hello") returns 5, of course. Thus:
Code:
send(s, "hello", 5, 0); // or strlen("hello")
Sends 5 characters: h, e, l, l, o.
Code:
send(s, "hello", 6, 0); // or strlen("hello") + 1
Sends 6 characters: h, e, l, l, o, \0. No garbage.

Now, you need some sort of serialization of data between the two. Unless you only plan on sending on string, you'll need something to break up the strings. A null terminator, or a length prefix. The recv()ing side will have to buffer the data appropriately.

send() is a very simple function. It sends a buffer of so many bytes. Likewise, recv() receives a buffer of so many bytes. Neither function knows anything about strings - that's way out of their scope. It send()s/recv()s data - ie, arrays of bytes. Period. You have to implement the protocol from point A to point B.
__________________
long time; /* know C? */
Unprecedented performance: Nothing ever ran this slow before.
Any sufficiently advanced bug is indistinguishable from a feature.
Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
The best way to accelerate an IBM is at 9.8 m/s/s.
recursion (re - cur' - zhun) n. 1. (see recursion)
Cactus_Hugger is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump


All times are GMT -6. The time now is 08:47 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22