Winsock difficulties

Started by
11 comments, last by rip-off 12 years, 6 months ago
Hello again everybody:

As a newbie to online game programming, I must say that Winsock in it's most basic form is not very practical to use.

I'm finding that turning everything into a char data stream which is often lumped together out of context in the send and recieve process is primitive. The stream socket doesn't seem to be able to match up one send with one receive on any consistent basis and often lumps several sends into one receive, which is a nightmare when you are depending on knowing what order the information is supposed to be in, in order to deciper it.

Sending string messages like a chat box are no problem but sending multiple player class variables is difficult when you are counting on then to arrive in a certain order.


Then you have to slow your progam down with Sleep calls to keep everything in line, and use little headers symbols and create loops to interpret all of that mess.

This cannot be what they intended. There must be a way to send objects that arrive at the other end in one piece and can be simply and easily unpacked and put in the right place.

Could MFC be the answer?
Advertisement
I'm assuming you're talking about TCP here, in which case, here's some important tips:

  • TCP is designed to be a stream-based protocol. That is, you put stuff in, you take stuff out - there is no intended correspondence between how much you put in and how much you get out at the other side. If you need to send discrete blocks, it's up to you to include information about how big each chunk is, so the other side of the connection can reconstruct the blocks.


  • TCP is also designed to be reliable, meaning that you will not get things "out of order." (There are also other guarantees, such as not losing the "2" in the sequence of sends "1 2 3".)


  • There is no need to slow things down or call Sleep. If you're finding that calling Sleep actually has any noticeable effect on your program's behavior, you're probably making a fundamental mistake someplace. If you're willing to share your code I'm sure we can help you figure out how to avoid this.


  • MFC is never the answer to anything, unless you are looking for a reason to want to kill yourself. If you think plain WInsock is bad, do yourself a favor and set fire to anyone who suggests you ever touch MFC. (And I'm only partly joking.)


  • That said, there are higher-level ways to work than just plain sockets. Plenty of libraries out there take care of things like sending discrete blocks of data for you, and so on. If you can give us a quick description of what you're wanting to do, perhaps someone can make a recommendation.


Hang in there - socket programming is a bit of a head-trip at first, but you'll get the hang of it smile.gif

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


As a newbie to online game programming, I must say that Winsock in it's most basic form is not very practical to use.


It's a lot more practical than trying to write raw bytes to a network card, which is the alternattive.
The reason sockets and networking is hard, is because networks and distributed systems are a hard problem! You can't hide hard problems behind easy facades without making some significant trade-offs. (If you want trade-offs, look into libraries like Enet or RakNet or whatever)


I'm finding that turning everything into a char data stream which is often lumped together out of context in the send and recieve process is primitive. The stream socket doesn't seem to be able to match up one send with one receive on any consistent basis and often lumps several sends into one receive, which is a nightmare when you are depending on knowing what order the information is supposed to be in, in order to deciper it.
[/quote]

Have you written save/restore functions for your game state to save files? It also needs to lump unrelated pieces of state into the same recepient.



Then you have to slow your progam down with Sleep calls to keep everything in line, and use little headers symbols and create loops to interpret all of that mess.
[/quote]

There is no place in game development where what you said is actually true. Sleep will *not* guarantee that your TCP packets are delimited when received. TCP is a stream protocol, just like a file on disk, and you should prefix each logical packet with some information so you know how to parse it out on the other end, just like with a file on disk. If you send a length first, it means you can wait on the receiving end until you have at least that many bytes in your buffer -- the packet is complete.


Could MFC be the answer?
[/quote]

No. MFC serialization is highly verbose, and will make your game use a lot more networking bandwidth than necessary, which will cause lag, disconnect issues, and other problems. This is generally true for any high-level serialization library (Java remoting, .Net remoting, etc).
enum Bool { True, False, FileNotFound };
Hello HP

Here's an example of the difficulties I am finding:

I am sending a vector of ints with a loop

char TheMsg[64];

for(int i=0; i<IntVec.size(); ++i)
for(int j=0; j<nClient; ++j)
{
sprintf(TheMsg,"$%d", IntVec);
send(Socket[j],(char*)TheMsg,strlen(TheMsg),0);
Sleep(100);
}


on the other end I receive it here:
ZeroMemory(gIncoming,sizeof(gIncoming));

int inDataLength=recv(Socket[n],
(char*)gIncoming,
sizeof(gIncoming)/sizeof(gIncoming[0]),
0);


With no Sleep call in the send loop the information comes out on the other end as
$21$13$34$2$12$14
Another words recv is processing it as one long string
With Sleep(20)it may come out something like this.
$21
$13$34
$2
$12
$14
With Sleep(100) in the sending loop is will come out as planned:
$21
$13
$34
$2
$12
$14
this is important because I plan on deciphering it with somthing like this:

switch(gIncoming[0])
{
case '$'
for(i=1; i<strlen(gIncoming); ++i)
{
string s+=gIncoming;
int number=atoi(s.c_str());
IntVec.push_back(number);










I'm assuming you're talking about TCP here, in which case, here's some important tips:

  • TCP is designed to be a stream-based protocol. That is, you put stuff in, you take stuff out - there is no intended correspondence between how much you put in and how much you get out at the other side. If you need to send discrete blocks, it's up to you to include information about how big each chunk is, so the other side of the connection can reconstruct the blocks.


  • TCP is also designed to be reliable, meaning that you will not get things "out of order." (There are also other guarantees, such as not losing the "2" in the sequence of sends "1 2 3".)


  • There is no need to slow things down or call Sleep. If you're finding that calling Sleep actually has any noticeable effect on your program's behavior, you're probably making a fundamental mistake someplace. If you're willing to share your code I'm sure we can help you figure out how to avoid this.


  • MFC is never the answer to anything, unless you are looking for a reason to want to kill yourself. If you think plain WInsock is bad, do yourself a favor and set fire to anyone who suggests you ever touch MFC. (And I'm only partly joking.)


  • That said, there are higher-level ways to work than just plain sockets. Plenty of libraries out there take care of things like sending discrete blocks of data for you, and so on. If you can give us a quick description of what you're wanting to do, perhaps someone can make a recommendation.


Hang in there - socket programming is a bit of a head-trip at first, but you'll get the hang of it smile.gif

With Sleep(100) in the sending loop is will come out as planned:

...

this is important because I plan on deciphering it with somthing like this:



What you're planning is wrong. That's not how you do it with TCP.

Note that Sleep(100) does not *guarantee* that recv() will come out as one string. If there are sufficient dropped packets, the sent data will be re-coalesced into bigger strings.
Treat writing to TCP like you would treat writing to a file. How would you write your protocol if you were writing to a file? Use the same solution to write to TCP.

Or use a library that packetizes data for you, so you call sendpacket() on one end, and receivepacket() on the other end, and it chops it up for you. Typically, that is done by first writing the length of the packet as a fixed number of bytes, and then writing the actual packet bytes. The receiving end will buffer data until it knows that it has a complete length; then it will buffer data until it has a complete packet; then it will return the packet. This may require remembering/buffering received data between successive calls.

This is, by the way, explained in links pointed to by the forum FAQ!
enum Bool { True, False, FileNotFound };
HP: Are you saying use ofstream outile in conjunction with a socket? Can you give an example in code of how that might work or give me a link to an actual example of the code that works. I didn't find anything in the forum FAQs directly on point.

Also can you give me a link to a DLL that does this.

This is what I was driving at in the first place. Like I said (I can't believe this is the way it is done!)

This is what I was driving at in the first place. Like I said (I can't believe this is the way it is done!)



Hearing you say that sounds a bit like someone who just learned to drive saying "Why do I have to stop at stop signs? I can't believe that this is the way it's done!"
The reason you can't believe it, is because you don't understand the underlying technologies, and what TCP sockets are (as compared to, say, a high-level RPC library, or a low-level networking packet).

I suggest you read a good networking textbook, such as TCP/IP Illustrated by Stevens (also mentioned in the FAQ, I think). If you don't want to buy it, it should be available for free at most libraries.
enum Bool { True, False, FileNotFound };
HP: Your hostility is unbelievable. I came to this forum seeking knowledge, not abuse.




[quote name='Deek880' timestamp='1316992154' post='4865896']
This is what I was driving at in the first place. Like I said (I can't believe this is the way it is done!)



Hearing you say that sounds a bit like someone who just learned to drive saying "Why do I have to stop at stop signs? I can't believe that this is the way it's done!"
The reason you can't believe it, is because you don't understand the underlying technologies, and what TCP sockets are (as compared to, say, a high-level RPC library, or a low-level networking packet).

I suggest you read a good networking textbook, such as TCP/IP Illustrated by Stevens (also mentioned in the FAQ, I think). If you don't want to buy it, it should be available for free at most libraries.
[/quote]

HP: Your hostility is unbelievable. I came to this forum seeking knowledge, not abuse.


I didn't hear such a hostility. He gave you a hint to where to find such knowledge (eg. the library) ;)


Once you have a better understanding of the means of communication you can come back to actually implement it.

You have to understand that networking is nothing simple and how much the library is doing for you is quite alot.
You still can ONLY use it certain ways.
TCP you either wait for the sends to finish (blocking) OR you keep checking to see if its completed (non-bocking) and go back to do other stuff and check again later.
There are higher level library functions that do alot of the work for you, but you still need to understand what the network does and what the limitations are.

With networks (like any multiprocessing process) you have a time domain involved which can have ALOT of
variability )especially thru the internet) and you have to handle that kind of situation programatically. Just like user text input you have to wait til
the entire input is done (a marker like <CR>) before you start processing it. In networks you send data of a size and the receiver
checks that the entire block of that size is received (thats either the library or YOU doing the check)

Its just the way things are. In some languages like Python the TCP libraries are VERY easy to use, but you STILL have to write the program
in a way that expects the information to be sent/received as discrete blocks and you either wait or keep coming back to check.
--------------------------------------------[size="1"]Ratings are Opinion, not Fact

This topic is closed to new replies.

Advertisement