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.
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.
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
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
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.
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.
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.
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.
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...
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.
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...
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...
And this is the sender...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; }
The answer to why the datagrams were not being sent has to do with the way windows multitasks.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; }
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.
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.
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.
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.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.
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.
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(); }