Thread: info on memset and recv

  1. #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 ?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    - 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.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    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()
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    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.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > 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.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    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.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > 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.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    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.
    Hope is the first step on the road to disappointment.

  9. #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

  10. #10
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    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.
    Hope is the first step on the road to disappointment.

  11. #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

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Because...

    man strlen
    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.
    Hope is the first step on the road to disappointment.

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    > 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.
    If at first you don't succeed, try writing your phone number on the exam paper.

  14. #14
    Registered User
    Join Date
    Dec 2007
    Posts
    930
    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 ?
    Last edited by Ducky; 11-08-2009 at 07:17 AM.
    Using Windows 10 with Code Blocks and MingW.

  15. #15
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    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)

Popular pages Recent additions subscribe to a feed