Jump to content
  • Advertisement
Sign in to follow this  
irbaboon

[WinSock TCP] A problem sending/receiving data

This topic is 2395 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey, for the last week or so I've been having a weird problem sending data...

First of all, the socket is set to nonblocking.

If my server, for example, is doing this:
SendData(Socket, "My data", true);
SendData(Socket, "My other data", true);

Then only the "My data" also the first packet, will be received by the client.
I noticed a workaround, I don't remember how... but I noticed it anyway.
That if I do this:
SendData(Socket, "My data", true);
Sleep(50);
SendData(Socket, "My other data", true);

Then it will work... Of course 50 is just a random number, it depends on how close the packets are sent after eachother.
The reason I don't just send it like:
SendData(Socket, "My data|My other data", true);
or similar, is because I want to be able to do:
SendData(Socket, "My data", true);
if (Bool) {
SendData(Socket, "My other data", true);
}


What happens if I don't use the Sleep(), is that both of the packets will be sent SUCCESSFULLY, but only the first one will be RECEIVED.
I actually get NO sign whatsoever of the second packet, not a single byte.

Here is the SendData function:
bool SendData(SOCKET sdsock, string sddata, bool sdlog)
{
const char *sdtemp = sddata.c_str();
unsigned int Sent = 0;
int Bytes = 0;
while (Sent < sddata.length()) {
Bytes = send(sdsock, sdtemp + Sent, sddata.length() - Sent, NULL);
if (Bytes == SOCKET_ERROR) {
if (sdlog) {
cout << "\nError while trying to send data: " << sdtemp << "\nBytes sent: " << Sent << "\nError: " << WSAGetLastError() << endl;
}
return false;
} else {
Sent += Bytes;
}
}
if (sdlog) {
cout << "\nSuccessfully sent data: " << sdtemp << "\nBytes sent: " << Sent << endl;
}
return true;
}


If you need any more information, then please tell me.
Thanks in advance :)

Edit: Updated the function to Cornstalk's fix. Note that this didn't fix the problem :(

Share this post


Link to post
Share on other sites
Advertisement
While this may not solve your problem, it looks like you've got a bug in your SendData function. When you call[font="Courier New"] Bytes = send(sdsock, sdtemp, sddata.length() - Sent, NULL);[/font] you are doing it almost right, except that you aren't increasing [font="Courier New"]sdtemp[/font]. It should look something more like [font="Courier New"]Bytes = send(sdsock, sdtemp + Sent, sddata.length() - Sent, NULL);[/font] in order to advance the starting point of buffer. Otherwise, you'll just be resending the data from the beginning of the buffer and not from where you left off.

Share this post


Link to post
Share on other sites

Oh, I see. Thank you. :)

While I can't see anything else in your SendData function that looks wrong, can we see the code where you're receiving the data?

Share this post


Link to post
Share on other sites
Sure.
The § is the symbol I just have to tell the function that "This is the end of the packet!".
It may be a bad solution, but it works.

Here's the function:
bool RecvData(SOCKET rdsock, string &rddata, bool rdlog)
{
char rdtemp[BUFFERSIZE + 1];
while (true) {
if (recv(rdsock, rdtemp, BUFFERSIZE, NULL) <= 0) {
if (rdlog) {
if (WSAGetLastError() != 10035) {
cout << "\nError while trying to receive data: " << rdtemp << "\nError: " << WSAGetLastError() << endl;
}
}
return false;
} else {
for (unsigned int i = 0; i < strlen(rdtemp); i++) {
rddata += rdtemp;
if (rdtemp == '§') {
if (rdlog) {
cout << "\nSuccessfully received data: " << rddata << endl;
}
return true;
}
}
if (rdlog) {
cout << "\nEnd of packet not found. Current data: " << rddata << endl;
}
return false;
}
}
}

Share this post


Link to post
Share on other sites
Well, in your OP, '§' isn't at the end of the strings your sending. Assuming it is at the end of the strings you're sending in your real code though, I'd say using '§' as a message delimiter is a bad idea. The reason is because '§' is not an ASCII character, so if you're compiler is using ASCII I'm not sure exactly how it's representing it in memory, but it can cause goofiness when trying to compare if a char equals '§'. Secondly, if your compiler is using UTF-8, '§' is a multi-byte character--that is, it can't be represented with just one byte, so again, testing if a char equals '§' causes goofiness and can't be done trivially. Try using a different character to test for the end of the message, like '\0' or something.

And one more thing: recv will return the number of bytes received. So you should be using the value returned to know how much data got put into your rdtemp buffer, rather than doing strlen (especially because recv doesn't null terminate your buffer, and strlen will be looking for '\0', so technically strlen could, and probably will, return the wrong value).

Share this post


Link to post
Share on other sites
Well, thanks for pointing those issues out.
However, I haven't noticed any goofiness about the § ... It has never caused me any problems, and I've used it for a while... But I'll look into changing it in the future.
I doubt that is the source of this problem though :)

And about the other thing. I don't think I quite get what you mean...

Share this post


Link to post
Share on other sites

And about the other thing. Do you mean the for loop should be like:
for (unsigned int i = 0; i < BytesReceived; i++) {
rddata += rdtemp;
if (rdtemp == '§') {
if (rdlog) {
cout << "\nSuccessfully received data: " << rddata << endl;
}
return true;
}
}


Yes, that's correct, assuming [font="'Courier New"]BytesReceived = recv(rdsock, rdtemp, BUFFERSIZE, NULL)[/font]

Share this post


Link to post
Share on other sites

Okay :)
Thanks for informing me about bugs in the functions, but the problem is still there :(

Sorry to hear the problem's still around. One more thought: you said it works if you Sleep(), but it doesn't if you don't Sleep(). It's possible that both messages get sent and received at the same time. That is, it's possible that the two calls to SendData are processed fast enough that RecvData is receiving both of them. recv doesn't care about how many times you've called send. All recv cares about is if there's data to be read in. If SendData is sending both datagrams quickly enough, which it probably is, recv just sees there's data ready to be received on the wire, even though there are two different datagrams waiting to be read in, recv just sees it as one continuous stream of data.

Hopefully that made a little sense. What you're probably doing is having recv receive both datagrams, but in your parsing of the data, you return after the end of the first datagram, and ignore the second datagram that is in the last part of the buffer. Try printing out how many bytes you receive and how long rddata is. You'll probably see that BytesReceived > rddata.length(), informing you that there is more data to be parsed, but currently you don't parse it.

You'll have to figure out a way to return the first datagram in rddata, but not throw away any extra data in the buffer you haven't parsed yet. I'd post a little coded example but I'm about to eat dinner. Give that a try (printing out BytesReceived and how long rddata is when you reach your delimiting character) and see what you find.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!