WSASend & WSARecv :: Winsock
Hi.
I am implementing a send and receive part of a simple message program. Everything seems to work okay, except the send and receive are not in sync.
For send, I use WSASend. I first send a "header" buffer with the same of the real data buffer. Next, I send the real data buffer.
For receive, I use WSARecv. I first receive the "header" buffer and determine its DWORD size. I then allocate a character array of that size. Next, I receive the real data buffer based on the size.
The problem is the "header" buffer I receive does not hold the correct data size. For example, let say the data size is 10 byte (10 characters). Instead of 10, I will get something at least in 90+ when I cast the "header" to a DWORD.
Here is the sample code for both send and receive. Please keep me updated if you find any known problem.
-----
char *data = new char[4];
data = "test";
DWORD bufferSize = static_cast(strlen(data)), sentSize = 0;
WSABUF bufferHDR,
bufferDATA;
char *header = new char[4];
CString sizeCnt;
sizeCnt.Format("%d", bufferSize);
strcpy(header, static_cast(sizeCnt));
bufferHDR.len = 4;
bufferHDR.buf = header;
// sending first data buffer contain the size
if (WSASend(socket, &bufferHDR, 1, &sentSize, MSG_OOB, 0, 0) == 0)
{
bufferDATA.len = bufferSize;
bufferDATA.buf = data;
sentSize = 0;
DWORD bufferProgress = 0;
// make sure all data gets sent
while (sentSize < bufferSize)
{
if (WSASend(m_ActiveSocket, &bufferDATA, 1, &bufferProgress, MSG_OOB, 0, 0) == 0)
{
sentSize += bufferProgress;
bufferProgress = 0;
}
else
{
DetermineErrorWSASend();
sentSize = bufferSize;
}
}
else
DetermineErrorWSASend();
-----
-----
DWORD bufferSize = 0,
receivedSize = 0,
flags = 0;
WSABUF bufferHDR,
bufferDATA;
char *header = new char[4], *data;
bufferHDR.len = 4;
bufferHDR.buf = header;
// reading first buffer to determine real data size
if (WSARecv(socket, &bufferHDR, 1, &receivedSize, &flags, 0, 0) == 0)
{
CString x;
bufferSize = static_cast(*bufferHDR.buf);
x.Format("%s%d", "bufferSize = ", bufferSize);
AfxMessageBox(x);
// allocating memory based on buffer size
data = new char[bufferSize];
bufferDATA.len = bufferSize;
bufferDATA.buf = data;
receivedSize = 0;
DWORD bufferProgress = 0;
// make sure all buffer get read
while (receivedSize < bufferSize)
{
if (WSARecv(socket, &bufferDATA, 1, &bufferProgress, &flags, 0, 0) == 0)
{
x.Format("%d", bufferProgress);
AfxMessageBox(x);
newData += *bufferDATA.buf;
receivedSize += bufferProgress;
}
else
{
DetermineErrorWSARecv();
receivedSize = bufferSize;
}
}
delete [] data;
delete [] header;
}
-----
Thanks,
Kuphryn
Here is your mistake:
Why are you trying to send the data length as a string? Why not just send bufferSize directly?
Next mistake:
Why are you sending your data out-of-band (MSG_OOB). Set WSASend''s flag parameter to ''0''.
Another mistake:
What you are doing here is setting bufferSize equal to the ASCII value of the first character in bufferHDR.buf (assuming your static_cast reads static_cast<DWORD>). This value is most likely 52, which corresponds to a character value of ''4''.
So from this point, your bufferSize is incorrect.
Lots of problems.
Dire Wolf
www.digitalfiends.com
CString sizeCnt;sizeCnt.Format("%d", bufferSize);strcpy(header, static_cast(sizeCnt));bufferHDR.len = 4;bufferHDR.buf = header;
Why are you trying to send the data length as a string? Why not just send bufferSize directly?
memcpy(bufferHDR, bufferSize, sizeof(bufferSize));
Next mistake:
if (WSASend(socket, &bufferHDR, 1, &sentSize, MSG_OOB, 0, 0) == 0){
Why are you sending your data out-of-band (MSG_OOB). Set WSASend''s flag parameter to ''0''.
Another mistake:
if (WSARecv(socket, &bufferHDR, 1, &receivedSize, &flags, 0, 0) == 0){CString x; bufferSize = static_cast(*bufferHDR.buf);
What you are doing here is setting bufferSize equal to the ASCII value of the first character in bufferHDR.buf (assuming your static_cast reads static_cast<DWORD>). This value is most likely 52, which corresponds to a character value of ''4''.
So from this point, your bufferSize is incorrect.
Lots of problems.
Dire Wolf
www.digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
www.digitalfiends.com
Another mistake:
You are just resending the same data over and over again.
You need to:
You had the correct intention but the wrong implementation.
Dire Wolf
www.digitalfiends.com
EDIT: Oh the same situation applies to your WSARecv as well. You need to continually offset the buffer pointer or you'll just overwrite what you've already received.
[edited by - Dire.Wolf on May 16, 2002 10:30:32 AM]
// make sure all data gets sentwhile (sentSize < bufferSize){ if (WSASend(m_ActiveSocket, &bufferDATA, 1, &bufferProgress, MSG_OOB, 0, 0) == 0){sentSize += bufferProgress;bufferProgress = 0;}
You are just resending the same data over and over again.
You need to:
// make sure all data gets sentWSABUF sendBuffer; DWORD sentSize = 0; while (sentSize < bufferSize){ sendBuffer.buf = bufferDATA.buf + sentSize; sendBuffer.len = bufferDATA.len - sentSize; if (WSASend(m_ActiveSocket, &sendBuffer , 1, &bufferProgress, MSG_OOB, 0, 0) == 0) { sentSize += bufferProgress; bufferProgress = 0; }
You had the correct intention but the wrong implementation.
Dire Wolf
www.digitalfiends.com
EDIT: Oh the same situation applies to your WSARecv as well. You need to continually offset the buffer pointer or you'll just overwrite what you've already received.
[edited by - Dire.Wolf on May 16, 2002 10:30:32 AM]
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
www.digitalfiends.com
Thanks.
You pointed out some keyed problem. Please give me some times to go over those possible problems.
I will try to post an update by tonight.
Thanks again,
Kuphryn
You pointed out some keyed problem. Please give me some times to go over those possible problems.
I will try to post an update by tonight.
Thanks again,
Kuphryn
Okay. I will try passing 0.
Here is one questions. I am using the WSAAsyncSelect I/O Mode. For example, let say I send two packages. The first package holds the size of the data buffer. The second package is the actual data buffer. Okay. That sounds easy enough. In WSAAsyncSelect I/O Mode, do I need to set a flag to basically determine whether an incoming package is the *header* or the *data buffer*?
This is hard to explain and I hope maybe someone will understand what I am implying. Here is a different sample.
-----
-> send header
-> send data
-----
-----
WSAAsyncSelect-> incoming message
-> receive header
WSAAsyncSelect-> incoming message
-> receive data
-----
In other words as soon as WSAAsyncSelect send notice of an incoming message, should I implement *two* calls to WSARecv *consecutively* or do I need a bool switch (header/data) type of implementation if WSAAsyncSelect sends a message for *each* incoming message.
Thanks,
Kuphryn
Here is one questions. I am using the WSAAsyncSelect I/O Mode. For example, let say I send two packages. The first package holds the size of the data buffer. The second package is the actual data buffer. Okay. That sounds easy enough. In WSAAsyncSelect I/O Mode, do I need to set a flag to basically determine whether an incoming package is the *header* or the *data buffer*?
This is hard to explain and I hope maybe someone will understand what I am implying. Here is a different sample.
-----
-> send header
-> send data
-----
-----
WSAAsyncSelect-> incoming message
-> receive header
WSAAsyncSelect-> incoming message
-> receive data
-----
In other words as soon as WSAAsyncSelect send notice of an incoming message, should I implement *two* calls to WSARecv *consecutively* or do I need a bool switch (header/data) type of implementation if WSAAsyncSelect sends a message for *each* incoming message.
Thanks,
Kuphryn
Thanks.
Winsock the and WSAAsyncSelect I/O Mode is more difficult than I anticipated. I will need another week or so to debug the program. There are some major flaws in my program. Most of which has to do with *timing*, i.e. when to send/receive header and when to send/receive data buffer. Remember that I am using the WSAAsyncSelect I/O Mode. It affects much mmore than I thought before I read MSDN.
Kuphryn
Winsock the and WSAAsyncSelect I/O Mode is more difficult than I anticipated. I will need another week or so to debug the program. There are some major flaws in my program. Most of which has to do with *timing*, i.e. when to send/receive header and when to send/receive data buffer. Remember that I am using the WSAAsyncSelect I/O Mode. It affects much mmore than I thought before I read MSDN.
Kuphryn
Okay. I have determine one major problem, or should I say characteristic of WSASend and/or WSARecv.
For some reason, I cannot call WSASend one after another. For example, let say I call WSASend to send a 4 byte buffer to the client indicating the size of the incoming data. That works find and the client receives the first WSASend package without problems. However, for some reason I cannot call WSASend the second time to send the actual package. The error on the *sending* side is WSAEFAULT:
// WSAEFAULT: "Bad address"
The error on the *receiving* side is WSAEWOULDBLOCK:
// WSAEWOULDBLOCK: "Resource temporarily unavailable"
The bottomline is I cannot send two data buffer consecutively. I am using the WSAAsyncSelect I/O Mode. Is there a specific specification that I missed as far as sending and receiving?
Please message me if you have any ideas.
Thanks,
Kuphryn
For some reason, I cannot call WSASend one after another. For example, let say I call WSASend to send a 4 byte buffer to the client indicating the size of the incoming data. That works find and the client receives the first WSASend package without problems. However, for some reason I cannot call WSASend the second time to send the actual package. The error on the *sending* side is WSAEFAULT:
// WSAEFAULT: "Bad address"
The error on the *receiving* side is WSAEWOULDBLOCK:
// WSAEWOULDBLOCK: "Resource temporarily unavailable"
The bottomline is I cannot send two data buffer consecutively. I am using the WSAAsyncSelect I/O Mode. Is there a specific specification that I missed as far as sending and receiving?
Please message me if you have any ideas.
Thanks,
Kuphryn
You must have an error in your code. That is not normal behaviour for WSASend/Recv. BTW What OS are you coding and testing on?
Dire Wolf
www.digitalfiends.com
Dire Wolf
www.digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
www.digitalfiends.com
Thanks.
I am developing the program under WindowsXP and Athlon 750mhz.
I am very, very close to getting everything working as planned. Here is where my progress. The program sends data perfectly (I believe). For example:
// Given WSABUF dataHDR, dataMessage
- send header buffer (dataHDR.Buf = data size)
- send data buffer (dataMessage.Buf = message)
// Given WSABUF inHDR, inMessage
- receive header buffer (inHDR = data size)
- use atol() to convert inHDR.Buf into an integer data size
- receive data buffer (inMessage.Buf = message)
Okay. I checked the actual receive size after calling WSARecv for the data buffer. The receive size is accurate, i.e. it received the exact number of byte that was sent. However, I cannot extract all characters from inMessage.Buf.
I use this code to extract the characters from inMessage.Buf
// CString message;
// message += *inMessage.Buf
The problem is the code above only extracts the *first* character in inMessage.Buf. I have considered that maybe only one character or byte is inside of inMessage.Buf; however, according to the check I did above on the actual received size, everything seems accurate.
Am I not converting inMessage.Buf correctly?
Kuphryn
I am developing the program under WindowsXP and Athlon 750mhz.
I am very, very close to getting everything working as planned. Here is where my progress. The program sends data perfectly (I believe). For example:
// Given WSABUF dataHDR, dataMessage
- send header buffer (dataHDR.Buf = data size)
- send data buffer (dataMessage.Buf = message)
// Given WSABUF inHDR, inMessage
- receive header buffer (inHDR = data size)
- use atol() to convert inHDR.Buf into an integer data size
- receive data buffer (inMessage.Buf = message)
Okay. I checked the actual receive size after calling WSARecv for the data buffer. The receive size is accurate, i.e. it received the exact number of byte that was sent. However, I cannot extract all characters from inMessage.Buf.
I use this code to extract the characters from inMessage.Buf
// CString message;
// message += *inMessage.Buf
The problem is the code above only extracts the *first* character in inMessage.Buf. I have considered that maybe only one character or byte is inside of inMessage.Buf; however, according to the check I did above on the actual received size, everything seems accurate.
Am I not converting inMessage.Buf correctly?
Kuphryn
You made an error:
When you deference an array like that you are telling the compiler that you want what the pointer points to.
Since inMessage.Buf is a char*, when you deference a char* what do you get? You get a char. That is the reason you are only getting the first character; you only asked for the first character.
Try changing your code to:
OR
The first method will be more efficient.
Hope this helps.
Regards,
Dire Wolf
www.digitalfiends.com
[edited by - Dire.Wolf on May 18, 2002 3:10:39 AM]
// CString message;// message += *inMessage.Buf
When you deference an array like that you are telling the compiler that you want what the pointer points to.
Since inMessage.Buf is a char*, when you deference a char* what do you get? You get a char. That is the reason you are only getting the first character; you only asked for the first character.
Try changing your code to:
CString message(inMessage.Buf);
OR
CString message;message += inMessage.Buf;
The first method will be more efficient.
Hope this helps.
Regards,
Dire Wolf
www.digitalfiends.com
[edited by - Dire.Wolf on May 18, 2002 3:10:39 AM]
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
www.digitalfiends.com
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement