Chapter 16 - Networking

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • Chapter 16 - Networking

    Here's the networking chapter - perhaps one of the more challenging to write, but quite rewarding. I learned a lot more than I thought I would!

    I just hope everyone can follow the code - it's not really easy....

    Oh - and please try to be as quick as possible on comments! We only have a few days left, and there's one more chapter to go!
    Mr.Mike
    Author, Programmer, Brewer, Patriot
  • RE: Chapter 16 - Networking

    "The best analogy is a pipe - what goes in will come out the other side, or you'll receive an error telling you something bad happened to the connection."

    This analogy needs a little work - pipes don't give you errors. A few more words should clean it up nicely. (Pipe bursts? Clogged?)

    --

    "By design, UDP is fairly lightweight but the messages arent guaranteed to arrive at their destination in any order, in one piece, or simply fall of the planet altogether. "

    Well, I'm glad they aren't guaranteed to fall off the planet...

    --

    "Winsock or Berkley?"

    I'm under the impression that the two socket types can talk to each other. Eg using Berkley for the server (which should be *NIX) and Winsock clients. You migth want to mention whether or not this is true.

    --

    "IP Classes"

    I'm under the impression that IP classes are not quite in use anymore, at least that's what I heard during my networking class (I WAS playing spider solitaire at the time, though)

    --

    "After all, there were a lot of programmers in the 1960's that never thought they'd need more than two digits to store the year, right? "

    Heh, there were quite a few in the 60's that used ONE digit to store the year.

    --

    You go into using the API, but I don't see anywhere how to actually put Berkley sockets on yoru computer (are they already there?), nor which library and includes to import. When I was trying to get Berkley sockets to work on my machine, I couldn't figure out how.

    --

    "" Address family: will always be PF_INET for communicating over the internet. Other address families include PF_IPX, PF_DECnet, PF_APPLETALK, PF_ATM, and PF_INET6."

    Perhaps a discussion of PF_INET6 is in order?

    --

    "" Socket type: Use SOCK_STREAM for connected byte streams. SOCK_DGRAM is for connectionless network communication and SOCK_RAW is for raw sockets, which let you write socket programs at a lower level than TCP or UDP.
    " Protocol: Use IPPROTO_TCP for TCP, and IPPROTO_UDP for UDP sockets. "

    Seems to me like SOCK_STREAM and DGRAM have important results when combined with TCP and UDP. I for one don't know what they are, though.

    --

    "Basically, don't call accept() until you have input on the listen socket connection, and can be sure you have at least one client ready to start talking."

    How do you check this?

    --

    "One common packet is a binary packet - the workhorse of our packet system. "

    Our research showed that text packets were more common and ideal. That happened to be in my research partner's findings, so I can't get into more detail.

    --

    This is a good chapter. It aligns with my research besides the above minor parts, and even includes information that we had argued over quite a bit (I ended up winning). You need more UDP vs. TCP, though.

    Serializing and sendin game objects seems to me to be a bad idea, but wrapping messages into a class and serializing THAT is a good idea. My research didn't cover this area.
    -Larrik Jaerico

    www.LarrikJ.com
  • I'd second the comment regarding text based vs binary data. If binary data is seen more often in games, some reasons why may be nice (even if it's the basic binary is ready to use vs text formats require parsing)

    -----
    Use the winsock2.h include to get berkley sockets
    Larrik
  • This address has two parts - the network ID number and the host ID number - the host ID is the individual computer.

    This might be a good place to use 207.200.39.91 as an example. Which part is the network ID and which part is the host ID?

    If the listen socket is set to non-blocking, and there are no client connections ready, it will return an error and put the listen socket in an unusable state. Basically, don't call accept() until you have input on the listen socket connection, and can be sure you have at least one client ready to start talking.

    Are you sure it will be unusable? I believe I actually called accept on a non blocking socket as part of an update routine with no problems. Basically, I made it so that a successful accept will cause a newconnection event to get sent into the system and a failure case on an 'accept' attempt causes the thread to go on its merry way. The last project I worked on involved a multi-client server that operated on a single thread. Perhaps I was misusing accept and should not have been using that method to poll listening socket for incoming connections.

    int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout );

    I did not use this in my last project. Why is using 'select' prefered over polling the nonblocking socket with accept/recv calls in an update loop? I can deduce that it has something to do with a limited buffer size on the low level sockets that must deal with incoming realtime data, but I'm not certain about that.

    int recv( SOCKET s, char* buffer, int length, int flags);

    Clarification Opportunity: So what happens when you pass in 10 for length and there are more than 10 bytes available to grab from that socket? Will the socket keep the ungrabbed data for you? What if you pass in 10 and there is only 8 available? (You actually address the latter situation inside 'NetSocket::HandleInput' by showing how you handle the return value.

    For Recv: MSG_PEEK peeks at the data but doesn't remove it from the input buffer, and MSG_OOB processes out of band data.

    As far as Winsock is concerned, MSG_PEEK and MSG_OOB are supposedly evil and broken or something. This semi-official website says not to use it: tangentsoft.net/wskfaq/newbie.html#peeking
    2.15 - What is peeking (MSG_PEEK), and why is it bad?
    Peeking is looking ahead in the TCP data stream: when you use the MSG_PEEK flag with recv(), it returns bytes from the stack's buffer without removing these from the buffer. (You can also do a form of peeking with the ioctlsocket() option FIONREAD.)

    Peeking is essentially never necessary: you can always read data into your own buffers and process it there. This is good, because peeking often causes problems. Indeed, it's so problematic it's earned a place on the Lame List and in Microsoft's Knowledge Base: see article Q192599 for specific info on the problems peeking causes with their Winsock stack.

    2.16 - What is out-of-band data (MSG_OOB), and why is it bad?
    Out-of-band (OOB) data is like a second data channel. The intent is to use the regular TCP data stream for most data and the OOB stream for "emergency" messages. The telnet protocol uses this for "interrupt" keystrokes like Ctrl-C, so that they don't have to wait on the remote peer to handle regular TCP data before the interrupt occurs. You can send OOB data by passing the MSG_OOB flag to send() and receive it by passing MSG_OOB to recv(). You can also get OOB data by setting the SO_OOBINLINE flag with setsockopt().

    OOB data is a useful concept, but unfortunately there are two conflicing interpretations of how OOB data should be handled at the stack level: the original description of OOB in the TCP protocol specification (RFC 793) was superceded by the "host requirements" spec (RFC 1122), but there are still many machines with RFC 793 OOB implementations. Section 3.5 in the Winsock 2 spec (version 2.2.2, as of this writing) discusses OOB, with details on why RFC 793 vs. RFC 1122 is a problem in section 3.5.2.

    OOB also isn't a fully functional second data channel: it's rather limited. So, never use OOB except when implementing legacy protocols like telnet which demand it. You can get reliable OOB-like behavior by simply using two data connections: one for normal data, and the second for emergency data.

    2.17 - If MSG_PEEK and MSG_OOB are bad, what do I pass for send() and recv()'s flags parameter?
    It's perfectly valid to pass 0 for send() and recv()'s flags parameter.


    // set nonblocking - accept() blocks under some odd circumstances otherwise SetBlocking(0);

    How 'bout using your own #defines that you referred to earlier in the chapter? :)

    Source Code

    1. #define BLOCKING (0)
    2. #define NONBLOCKING(1)


    ___
    From the code samples, I am not clear on whether this entire sample operates on a single thread or if the reader will need to implement multithreading to get functions like 'NetListenSocket::AcceptConnection' to work. Is the call to 'accept' inside this function a blocking call? Overall, if multithreading is involved in the implementation of the sample, I'd like to know more details about where I'd implement multithreading, otherwise I'd like reassurance that I won't have to worry about it.

    There is much more to network programming that I've had the pages to teach you here. First and foremost, remote games need to be very smart about handling slow internet connectivity by predicting moves and handing things elegantly when those predictions are wrong. For enterprise games like Star Wars Galaxies, Everquest, or Ultima Online you have to take the simple architecture in this book and extend it into a hierarchy of server computers - a task that could use a book all by itself to cover well.

    So you've alluded to prediction algorithms and server scalability. I'd like to add a purple duck here by saying that you might also want to mention cheat detection/prevention somewhere in this paragraph.

    ___
    I like this chapter lots.

    The post was edited 1 time, last by Kain ().

  • RE: Chapter 16 - Networking

    Thanks for the comments - I laughed out load when I read about the 1 digit year. Now THAT's optimistic!

    I know the pipe is something of a rough analogy - but it is a very UNIX style one.

    IP classes are most certainly in use, but they tend to be aggregated and subleased like crazy, so I guess they aren't as relavent to the generic internet user. They still mean the world to anyone programming routers and such...

    IPv6 is still so new I don't even know if my ISP supports routing it.....maybe I shouldn't mention it!

    Text packets are more common???? Isn't 90% of the data transmitted over the internet porn movies?????
    HAHAHA.
    Mr.Mike
    Author, Programmer, Brewer, Patriot
  • Good comments about the binary vs. text packets. I added a new paragraph to clarify the statement.
    Mr.Mike
    Author, Programmer, Brewer, Patriot
  • Excelelnt comments Kain - thanks again as always!
    Mr.Mike
    Author, Programmer, Brewer, Patriot