|
-
October 19th, 2005, 10:08 PM
#1
UDP + recv() + MSG_PEEK = WSAEMSGSIZE
I was wondering if it is safe to "peek" at the buffer when using UDP as the selected protcol in Winsock. The recv() function fails with WSAEMSGSIZE, so I'm wondering if the data is lost.
Thanks.
::EDIT::
I just tested the application by ignoring the WSAEMSGSIZE error and the peek worked successfully and then another call after that to receive the data without MSG_PEEK worked properly!
Why would it report this error if it isn't true? I'm also curious to know why data that you don't receive in a single call is erased from the receive buffer. For example, if there is 10 bytes in the receive buffer and I only receive 5 bytes in a single call to recv(), the other remaining 5 bytes are erased?? Why would UDP do this?
Thanks.
Last edited by MrDoomMaster; October 19th, 2005 at 10:28 PM.
--MrDoomMaster
--C++ Game Programmer
Don't forget to rate me if I was helpful!
-
October 20th, 2005, 12:43 AM
#2
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
if u r using MSG_PEEK in recv call then it means u did not want to remove such data from System's Buffer and this also returns the number of pending bytes.
 Originally Posted by MrDoomMaster
I just tested the application by ignoring the WSAEMSGSIZE error and the peek worked successfully and then another call after that to receive the data without MSG_PEEK worked properly!
u r doing well to receive message properly but Message peeking is bad approch.
 Originally Posted by MSDN
recv() with MSG_PEEK should generally be avoided. It is a very inefficient way to retrieve data and definitely not recommended if you care about performance. A much better solution would be to simply receive the data into user buffers and use it directly from there.
In ur case if u r developing sending and receiving both apps then keep ur buffer same at both ends or atleast ur receiving buffer should be quite enough to receive data.
Care should be taken while sending messages because the following reasons can cause WSAMSGSIZE error.
 Originally Posted by MSDN
Reasons for WSAEMSGSIZE : A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
 Originally Posted by MrDoomMaster
I'm also curious to know why data that you don't receive in a single call is erased from the receive buffer. For example, if there is 10 bytes in the receive buffer and I only receive 5 bytes in a single call to recv(), the other remaining 5 bytes are erased?? Why would UDP do this?
For datagram sockets, data is extracted from the first enqueued datagram, up to the size of the buffer supplied. If the datagram is larger than the buffer supplied, the buffer is filled with the first part of the datagram, the excess data is lost, and recv() returns the error WSAEMSGSIZE. I dont know why but its defined under Windows Sockets definitions of regular Berkeley error constants.
A Person who is polite is given goodness and a person who is away from Politeness is away from Goodness.
NAUMAAN
-
October 20th, 2005, 01:10 AM
#3
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Please send me the procedure how can i see your code?Am i able to see it?.I am a new member in this site.
-
October 20th, 2005, 11:20 AM
#4
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Well I generally NEED MSG_PEEK or else I cannot receive data properly.
My packets are actually structures. The first BYTE of every structure has a special ID number that identifies what kind of structure it is.
For example, take this structure:
Code:
struct Packet
{
private:
const unsigned char ID;
public:
int X;
int Y;
Packet(void) :
ID(0x01),
X(0),
Y(0)
{
}
};
And when I send this packet, I simply cast any object of this structure to a void pointer and send the raw data. On the receiving end, I first PEEK the first byte of the buffer to see what ID number the packet holds, and then I call receive again (without MSG_PEEK) to actually receive the entire packet.
For example:
Code:
unsigned char PacketID;
if(net.Receive(&PacketID, sizeof(unsigned char), true) != SUCCESS)
throw "Receive FAILED (peek)";
switch(PacketID)
{
case 0x01:
{
Packet data;
if(net.Receive(&data, sizeof(Packet)) != SUCCESS)
throw "Receive FAILED (Packet 0x01)";
cout << "Packet received! Data: (" << data.X << ',' << data.Y << ")\n";
break;
}
default:
{
throw "Invalid Packet Received";
}
}
The first call to Receive has three parameters, the third parameter is set to "true" for MSG_PEEK, and "false" for no peek.
The second call to Receive is simply a different overloaded version of the first receive function that simply assumes "false" for the third parameter in all situations.
I hope everyone can understand my dilemma now. I honestly don't see any other way to do this...
--MrDoomMaster
--C++ Game Programmer
Don't forget to rate me if I was helpful!
-
October 21st, 2005, 02:07 AM
#5
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Its quite ok as ur problem seems but if u know the maximum size of a message required by u, then u can call recv with that size of buffer without MSG_PEEK and then check what kind of packet u received like u already checking.
A Person who is polite is given goodness and a person who is away from Politeness is away from Goodness.
NAUMAAN
-
October 21st, 2005, 11:50 AM
#6
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Well, since I am using this code in a DirectX game, I suppose I can't really use MSG_PEEK, since it has been mentioned that it degrades performance.
Anyone have a different idea on how to send packets more efficiently?
--MrDoomMaster
--C++ Game Programmer
Don't forget to rate me if I was helpful!
-
October 25th, 2005, 01:05 PM
#7
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Sorry but I really would like some suggestions on my previous inquiry. Thanks!
--MrDoomMaster
--C++ Game Programmer
Don't forget to rate me if I was helpful!
-
October 26th, 2005, 12:11 AM
#8
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
 Originally Posted by MrDoomMaster
Well, since I am using this code in a DirectX game, I suppose I can't really use MSG_PEEK, since it has been mentioned that it degrades performance.
Anyone have a different idea on how to send packets more efficiently?
When it comes to UDP, it is always better for a send to result in one datagram. What I mean is if the data is more that the MTU (actually after subtracting the IP and UDP header length), the IP packet gets fragmented. And fragmentation is always better to be avoided, including performance degradation reasons.
So UDP is good if
#1 You don't care if the packet reaches or not.
#2 The data in one send does not go beyond the network MTU
#3 A message unit is containted in a single datagram.
#4 The receive side always have sufficient buffer to hold/receive the data.
As a side note, as already mentioned, MSG_PEEK must always be avoided. Not only it is highly inefficienet, it is buggy as well(regarding to the count).
Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.
* While posting code sections please use CODE tags
* Please check the codeguru FAQ and do a little search to see if your question have been answered before.
* Like a post, Rate The Post
* I blog: Network programming, Bible
I do all things thru CHRIST who strengthens me
-
October 26th, 2005, 12:36 PM
#9
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
That's nice information. Although, I do not know my network MTU.
I still would like to know how I can do the following:
1) Send an object of a structure cast to void* (therefore sending it as raw data)
2) Receive the data and know which structure to cast it back to *without* using MSG_PEEK.
Thanks.
--MrDoomMaster
--C++ Game Programmer
Don't forget to rate me if I was helpful!
-
October 26th, 2005, 08:32 PM
#10
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
As Naumann suggested, if there is a reasonable maximum to the size of all the message that will ever be sent, then you can do the following.
Define an array of bytes (or, char's) as large as the maximum, and then call Receive() to receive everything that the socket wants to send into this array. Do this without any MSG_PEEKing. Now, inspect the first byte (or, unsigned char) of the data in the received buffer in order to determine the packet type, and then cast a pointer to the array to the determined type. For example:
Code:
char buffer[1024]; // some maximum size
if ( net.Receive( buffer, 1024 ) != SUCCESS )
/* handle error */
unsigned char PacketID = buffer[0];
switch(PacketID)
{
case 0x01:
{
PacketTypeOne* pData = (PacketTypeOne*) buffer;
pData->access the data in the packet
break;
}
case 0x02:
{
PacketTypeTwo* pData = (PacketTypeTwo*) buffer;
pData->access the data
break;
}
// ... etc ...
}
Mike
-
October 27th, 2005, 07:33 AM
#11
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
 Originally Posted by MrDoomMaster
That's nice information. Although, I do not know my network MTU.
This is a little bit tricky. There are 3 scenarios you meet.
- Both machines on the same network
- Both machines on different networks
- Both machines on different networks but interconnected somewere by a small MTU channel
In the first case it is easy. Second case the MTU will be smallest of the client/server network. In the third case you may have to use some MTU discovering tools (like tracepath in linux).
MTU is 1500 for ethernet. The payload you can use will be 1500-20-8 = 1472.(20 bytes for IP header and 8 for UDP) You can get the network using GetIfTable(). If you are using TCP it does all these for you. That is why when you are using UDP you loose effeciency rather than gaining(among several other reasons). While adding these efficiencies over UDP is simply like reinventing the wheel(often at the end you'll get a worse wheel).
 Originally Posted by MrDoomMaster
I still would like to know how I can do the following:
1) Send an object of a structure cast to void* (therefore sending it as raw data)
2) Receive the data and know which structure to cast it back to *without* using MSG_PEEK.
Thanks.
I guess you already got the anwers for this. Mike has posted an excellent way. You can find one that shows using union and structure. Look at the following faq
Last edited by Mathew Joy; October 27th, 2005 at 07:36 AM.
Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.
* While posting code sections please use CODE tags
* Please check the codeguru FAQ and do a little search to see if your question have been answered before.
* Like a post, Rate The Post
* I blog: Network programming, Bible
I do all things thru CHRIST who strengthens me
-
October 27th, 2005, 01:31 PM
#12
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Well UDP is supposedly faster than TCP because there is no error or packet checking. That is why I choose it, since my application depends on speed.
--MrDoomMaster
--C++ Game Programmer
Don't forget to rate me if I was helpful!
-
October 27th, 2005, 02:41 PM
#13
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Since this is for a game-based application, you might find this 11-part article to be helpful: "Game Engine Anatomy 101" at http://www.extremetech.com/article2/0,1697,594,00.asp
Part VII (at http://www.extremetech.com/article2/0,1697,482,00.asp ) discusses UDP.
In general, I found the article to be a nice read.
Mike
-
October 27th, 2005, 03:02 PM
#14
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
Here's another example of packet-type identification, which is based on a union. I found the example at http://www.gamedev.net/community/for...sp?forum_id=15. In general, if you have not been there already, you really should visit and search over at the www.gamedev.net site, since you're writing a game:
Code:
struct PlayerPosPacket {
unsigned short code;
unsigned short player;
float pos_x, pos_y, pos_z;
float vel_x, vel_y, vel_z;
float heading;
};
PlayerPosPacket packet;
packet.code = PLAYER_POS;
packet.player = thePlayerId;
...
int r = sendto( sock, (char const *)&packet, sizeof(packet), 0, (sockaddr *)&dst_addr, sizeof(dst_addr) );
if( r < 0 ) { error(sock); }
union {
PlayerPosPacket playerPos;
SomeOtherKindOfPacket someOther;
} recvPacket;
int r = recvfrom( sock, (char *)&recvPacket, sizeof( recvPacket ), 0, (sockaddr *)&src_addr, sizeof(src_addr) );
if( r < 0 ) { error(sock); }
/* assume all packet types start with unsigned short code; */
switch( recvPacket.playerPos.code ) {
case PLAYER_POS:
if( r != sizeof(recvPacket.playerPos) ) { formatError(); }
do_playerPos( recvPacket.playerPos, src_addr );
break;
case SOME_OTHER:
if( r != sizeof(recvPacket.someOther) ) { formatError(); }
do_someOther( recvPacket.someOther, src_addr );
break;
...
}
Mike
-
October 28th, 2005, 12:39 AM
#15
Re: WinsockUDP + recv() + MSG_PEEK = WSAEMSGSIZE
 Originally Posted by MrDoomMaster
Well UDP is supposedly faster than TCP because there is no error or packet checking.
UDP infact has error checking. Only thing is, it does not let the application know or attempt to retransmit. The erroneous packet is thrown away.
I don't know what you meant by packet checking. If you meant out-of-order packets or duplicate packets, then it is true. Gaming applications does fine with UDP, because one resultant packet will usually be small. Moreover loss of a packet won't mean anything much. Using UDP as it is, is obviously faster than TCP. Attempt to build reliability on UDP effectively make it worse than TCP. TCP is well tuned for effecient interactive and bulk data transfer. And when I say effecient it means fast as well.
Even if our suggestions didn't help, please post the answer once you find it. We took the effort to help you, please return it to others.
* While posting code sections please use CODE tags
* Please check the codeguru FAQ and do a little search to see if your question have been answered before.
* Like a post, Rate The Post
* I blog: Network programming, Bible
I do all things thru CHRIST who strengthens me
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|