Thread: need winsock 2 info...

  1. #1
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547

    need winsock 2 info...

    I've been tearing a strip out of the web and I'm not finding any answers...

    In windows winsock...

    1) Is there an embedded maximum packet size for UDP and what is it?
    2) What is the default receive buffer size?

    Thanks.

  2. #2
    Registered User
    Join Date
    Mar 2010
    Posts
    68
    Well, 576 is the total maximum size of a UDP packet that will be guaranteed NOT to be fragmented (this 576 includes the headers as well). So, you are left with . . . ..

    -20 bytes for the IP header
    -8 bytes for the UDP header
    -18 bytes for the ehternetheader(not sure about this one . . someone correct me?)

    530 bytes left of usable payload space.

    Now, you should be able to work with a size of 1500 bytes, but it is not guaranteed not to be fragmented. Also, you do not need to worry if a packet does get fragmented, as it is reassembled in a lower layer and you don't even know it happens. Fragmentation should be avoided if possible because it increases the chance of a dropped packet.

    Generally, here is what happens when and why fragmentation occurs....


    You send a udp packet out to another computer over the internet, on the packets path it goes through other routers, on its way, and some of those routers will break your packets up into smaller chunks(fragment). You have no control over this! The packets still continue on their path until they reach their destination where the other end assembles the packet into a single packet --provided they all are received. If one packet does not arrive, then the whole packet is discarded.

    Hope that helps :P\

    Topic with a bit of information

    Fragmented UDP packets? - GameDev.Net Discussion Forums

  3. #3
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by smasherprog View Post
    Well, 576 is the total maximum size of a UDP packet that will be guaranteed NOT to be fragmented (this 576 includes the headers as well). So, you are left with . . . ..
    Actually that helps enormously.

    Through expermentation I discovered that Winsock2 has an imbedded 64k (65536 bytes) limit on datagram size; not that I plan sending anything even 1/10th that big. Also the default Rx and Tx buffers for each open socket are 8192 bytes.

    Process of elimination, I now know this isn't the problem.

    Most datagrams on this project are 10 bytes or less but there are two that max out at 1090 bytes... oddly it's the small ones that are giving me fits.

    In another thread Elysia suggested it might be data alignment problems since I'm transferring C stucts in a couple of the ones that sometimes misbehave. I tried this because they have several WORD and DWORD elements and encoding and decoding is beyond simple... This now warrants deeper investigation.

    Thanks for a very helpful reply.
    Last edited by CommonTater; 10-02-2010 at 10:03 AM. Reason: typos

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    The problem of sending raw structs is one (or two) issues known as

    Endian
    Endianness - Wikipedia, the free encyclopedia

    Alignment
    Data structure alignment - Wikipedia, the free encyclopedia

    Fixing alignment is generally possible with "#pragma pack" kludges and the like.
    Fixing endian is an altogether much harder problem. Typically, you should use the htons() and similar functions to ensure that multi-byte data types are consistently represented on the wire.
    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.

  5. #5
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Salem View Post
    The problem of sending raw structs is one (or two) issues known as

    Endian
    Endianness - Wikipedia, the free encyclopedia

    Alignment
    Data structure alignment - Wikipedia, the free encyclopedia

    Fixing alignment is generally possible with "#pragma pack" kludges and the like.
    Fixing endian is an altogether much harder problem. Typically, you should use the htons() and similar functions to ensure that multi-byte data types are consistently represented on the wire.
    I was aware of the first issue but the second one took me by surprise.

    These datagrams I'm sending travel only within LAN confines and only between matched client-server pairs. What I seem to be discovering is that data alignment varies even between windows versions... some of the servers on XP some on Windows 7 ... While the whole thing mostly works, I still get the odd time when a smaller datagram isn't sent. (I have "sniffed" it and it is not being sent)

    The pragma doesn't appear to help much as there are still datagrams that don't get sent.

    As is so common in the computer industry I appear to have tripped over convenience here. I'm presently experimenting with different ideas to see which works best...

    Thanks to you also for an informative reply.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    UDP isn´t a robust protocol. The only guarantee is that if you get it, it will be intact.

    There are several places where it could be dropped.
    - The transmit protocol stack
    - Along the wire (or any router along the way)
    - The receiver protocol stack.

    As for alignment between windows versions, are all the images built with the same compiler?
    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.

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Salem View Post
    UDP isn´t a robust protocol. The only guarantee is that if you get it, it will be intact.

    There are several places where it could be dropped.
    - The transmit protocol stack
    - Along the wire (or any router along the way)
    - The receiver protocol stack.

    As for alignment between windows versions, are all the images built with the same compiler?
    Yes all are built with the same compiler, at the same time. To guard as much as possible I wrote a static comms library that is common to both client and server, linked in at compile time. They should both have an identical understanding of the information.

    Most of these datagrams are tiny... typically 6 bytes, conveying a DWORD passcode and a single command BYTE. On the original version, made for XP, I've never yet seen a packet dropped or mangled. But on this version, which now has to work on either win7 or XP, the reliability is way less than 20%. I am beginning to wonder if I've encountered an OS bug in win7.

    As for where it's being dropped... The datagram never leaves the Win7 host machine. It is simply not being sent. The bigger ones, with up to 512 bytes of data, always work... it's the little ones that get lost. But it's the little ones I need to keep everything synchronized. They convey: Ready, Wait, Done, Stop, etc.

  8. #8
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    The plot thickens... I just knocked together a quick test program using my datagram library (the one I'm having problems with), had two machines sending to each other and checking the data transferred... One machine is XP the other Win7... 100,000+ packets of random sizes and random content, both ways, with 0 errors.

    Now I'm really puzzled...

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    On the win7 machine, look at the network connection properties to see how many packets are dropped.

    There might be an API to explore "why" they´re being dropped.
    I don´t have win7, so this is all guessing
    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.

  10. #10
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Salem View Post
    On the win7 machine, look at the network connection properties to see how many packets are dropped.

    There might be an API to explore "why" they´re being dropped.
    I don´t have win7, so this is all guessing
    Thank you for the reply. Unfortunately Win7 is so totally obfuscated in some areas that I've been entirely unable to find any information about dropped packets. Sniffing the port revealed little except that when miscommunication occurs it is always because the packet never got sent.

    But last night's torture test would seem to indicate that packages do get sent with near 100% reliability both from Win7 and XP... So at this point I'm at a loss to explain the behavior.

    Of course there's a chance it's something in my code that I haven't found yet... but at this moment I have no clue what that might be.



    I'm thinking my best bet, at least for now, is to continue working on other parts of the project and come back to this one later...

    Thanks everyone for trying to help.
    Last edited by CommonTater; 10-04-2010 at 12:57 PM. Reason: I have GOT to learn to spell...

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Update... I believe I may have my answer...

    The code below is typical of the way I've been doing things... (be kind!)...

    This snippet housecleans an array of known client programs...
    Code:
    // close a client program
    VOID TrackerDelRemote(SLOT RemSlot)
      { WCHAR ll[MAX_LOGLINE];
        WCHAR hn[MAX_HOSTNAME];
        // guard for bad slot
        if (Remotes[RemSlot] == NULL)
          return;
        // kill it
        SendDatagram(&Remotes[RemSlot]->Owner,PassCode,
                                              RM_KILLREMOTE,&RemSlot,sizeof(SLOT));
        // kludge to allow multitasking
        Sleep(100);                               <---- this is the fix
        // log
        GetHostName(&Remotes[RemSlot]->Owner,hn);
        swprintf(ll,MAX_LOGLINE,L"\"%ls\" on %ls from slot %d",
                  Programs[Remotes[RemSlot]->PgmSlot]->Remote,hn,RemSlot);
        AddToLog(L"Close",ll);
        // release memory
        free(Remotes[RemSlot]);
        Remotes[RemSlot] = NULL; }
    And this is the sender...

    Code:
    // compose and send datagrams
    INT SendDatagram(PSOCKADDR To,DWORD PassCode,BYTE Command,PVOID Data,INT DataSize)
      { INT       sdgram;       // datagram size
        FD_SET    st;           // socket to be tested
        TIMEVAL   tv;           // wait time
        INT       res;
        // set up wait time
        st.fd_count    = 1;
        st.fd_array[0] = hSocket;
        tv.tv_sec      = 5;
        tv.tv_usec     = 0; 
        // insert packet values  
        *((PDWORD)txDgram + DGRAM_PASS) = PassCode;
        *((PBYTE) txDgram + DGRAM_CMD)  = Command;
        if ((Data != NULL) && (DataSize > 0))
          memcpy(txDgram + DGRAM_DATA,Data,DataSize);
        sdgram = DataSize + DGRAM_DATA; 
        // send it
        res = sendto(hSocket,txDgram,sdgram,0,To,sizeof(SOCKADDR)); 
        select(1,NULL,&st,NULL,&tv); 
        return res; }
    The answer to why the datagrams were not being sent has to do with the way windows multitasks.

    When you launch a message from your program's dispatcher loop, you are working in a single timeslice. The program instance is blocked until all your functions return to the dispatcher loop. Winsock is attached to this instance by it's socket handle.

    The first code snippet is launched by a message from the dispatcher, it locates the necessary address data, sends it to the second snippet which composes the datagram and then upon return from creating the datagram, it cleans up the memory from the closed client and finally returns to the windows dispatcher... all without allowing anything else to run... I was inadvertently deleting the address for the datagram before it was sent.

    The answer proved simple enough... release the time slice. Note the red marking in the first snippet Sleep(100); Sleep releases the time slice and lets the system multitask... the datagram gets sent. I will probably trim that time down somewhat but for now it's working... and it's only in a couple of spots where there's no back and forth so a short delay is not an issue.

    I hate kludges like this but I just don't see any other way to get the job done.

    Again thanks to everyone who chipped in to help. It is appreciated.
    Last edited by CommonTater; 10-05-2010 at 12:59 PM.

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Nice, but I think you need to solve it another way.
    100mS might not be enough under heavy load say, and you´re back to the same issue.

    Is it possible for the remote to send some kind of ACK to the RM_KILLREMOTE?
    Removing the entry on the ACK would seem to be a lot safer.
    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.

  13. #13
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Salem View Post
    Nice, but I think you need to solve it another way.
    100mS might not be enough under heavy load say, and you´re back to the same issue.
    Agreed. This is a kludge until I figure out a better way. It lets me move on to other parts of the project while I think about better solutions.


    Is it possible for the remote to send some kind of ACK to the RM_KILLREMOTE?
    Removing the entry on the ACK would seem to be a lot safer.
    That thought occured. And I agree it would solve the problem. But at that moment there's no gurantee the client is even there. If the ACK never came I'd have an even bigger problem trying to garbage collect the list.



    Right now, I'm more concerned about why winsock sendto() --in full blocking mode-- would return before the message is actually sent and even more troubled to discover that with unknowable completion status they only store pointers, requiring us to retain the data at least until completion.

    "Now exactly how long did you say I need to keep these????"

    This strikes me as a very very bad idea... If they are going to deal in unknowns they should be either a) providing signalling or b) buffering copies of the data... I've wasted more than a week on this silliness, and I still don't have a good answer.
    Last edited by CommonTater; 10-06-2010 at 12:02 PM.

  14. #14
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Another update on this ongoing mess...

    I got thinking about the way this project works. It's multi-threaded and some stuff is sent from more than one thread. It occured to me that my receiver thread (which works like a windows message tosser) and the other threads that may be sending could be colliding causing the sendto failure... So I added some interprocess signalling to prevent it from trying to receive and send at the same time... So far so good.

    In the snippets below note how I signal the rxHold object when sending. This effectively stops the recvfrom() call from blocking the port at that moment. Been running it all day and not one dropped datagram. ... The second section below is it's own tread, launched at startup... The first snippet is actually called by different threads at different points in the programs...

    Once again, thanks to all who chipped in to help.

    Code:
    /////////////////////////////////////////////////////////////////////////////////////////
    // send datagrams
    //
    
    // compose and send datagrams
    BOOL SendDatagram(SOCKADDR To,DWORD PassCode,BYTE Command,PVOID Data,INT DataSize)
      { INT       sdgram;                     // datagram size
        FD_SET    st;                         // socket to be tested
        TIMEVAL   tv;                         // wait time
        CHAR      dg[MAX_DATAGRAM] = {0};     // datagram data
        // set up wait time
        st.fd_count    = 1;
        st.fd_array[0] = hSocket;
        tv.tv_sec      = 5;
        tv.tv_usec     = 0; 
        // insert packet values  
        *((PDWORD)dg + DGRAM_PASS) = PassCode;
        *((PBYTE) dg + DGRAM_CMD)  = Command;
        if ((Data != NULL) && (DataSize > 0))
          memcpy(dg + DGRAM_DATA,Data,DataSize);
        sdgram = DataSize + DGRAM_DATA; 
        // send it
        if (select(1,NULL,&st,NULL,&tv) > 0 )
          { ResetEvent(rxHold);
            sendto(hSocket,dg,sdgram,0,&To,sizeof(SOCKADDR));
            SetEvent(rxHold); }
        return 0; }
    
    
    /////////////////////////////////////////////////////////////////////////////////////////
    // Receive Datagrams
    //
           
    // datagram tosser prototype
    BOOL CALLBACK (*Toss)(SOCKADDR,DWORD,BYTE,LPVOID);
    
    // receiver thread 
    DWORD Listener(LPVOID DgramTosser)
      { INT       sf;               // size of reply addr     
        SOCKADDR  rf;               // received from
        FD_SET    st;               // socket to be tested
        CHAR      dg[MAX_DATAGRAM]; // datagram data
        // set up wait time
        st.fd_count    = 1;
        st.fd_array[0] = hSocket;
       // set callback
        Toss = DgramTosser;
        // receiver loop
        while(!KillWSA)
          { // set address size
            sf = sizeof(SOCKADDR);
            // receive datagram
            if (select(1,&st,NULL,NULL,NULL) > 0)
              { WaitForSingleObject(rxHold,INFINITE);
                if (recvfrom(hSocket,dg,MAX_DATAGRAM,0,&rf,&sf) != SOCKET_ERROR)
                  { Toss(rf, *((PDWORD) dg + DGRAM_PASS),
                             *((PBYTE)  dg + DGRAM_CMD), 
                             dg + DGRAM_DATA); } } }
        return WSAGetLastError(); }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. help displaying info from structure
    By kisiellll in forum C Programming
    Replies: 6
    Last Post: 04-04-2009, 12:51 PM
  2. Winsock issues
    By tjpanda in forum Windows Programming
    Replies: 3
    Last Post: 12-04-2008, 08:32 AM
  3. Question about getting an info class from another Form
    By Joelito in forum C# Programming
    Replies: 0
    Last Post: 10-16-2006, 01:02 PM
  4. Help doing an e-mail program in c...
    By Tyler_Durden in forum C Programming
    Replies: 88
    Last Post: 01-02-2005, 03:12 PM
  5. Where do I initialize Winsock and catch messages for it?
    By Lithorien in forum Windows Programming
    Replies: 10
    Last Post: 12-30-2004, 12:11 PM