[9/13/2013] Iso's awesome guide to networking

A forum to store posts deemed exceptionally wise and useful
Post Reply

Was this guide helpful to you?

Yes!
6
50%
Nope, you suck!
0
No votes
This inquiry does not match my intellectual level.
1
8%
I like doughnuts ...
5
42%
 
Total votes: 12

Isomorphix
Posts: 16
Joined: Fri Aug 16, 2013 5:08 pm

[9/13/2013] Iso's awesome guide to networking

Post by Isomorphix »

Hello guys, I'm kinda new in 3D programming and Irrlicht so I can't help much with those stuff. But there's something I know very well and that's networking.

So, why networking? Well the answer is simple, with the increase in bandwidth because of ever-growing fiber-optic installations games gain a unique ( since '00 ) ability; ingame-interaction with other players.
No matter how advanced AI's become, the difference will always be noticable. Single-player games don't have the human touch that multiplayer ones do.

Note to self: Microsoft dropped Xbox one's - check in every 24h or ban - policy. So yay ~

If you have read Beej's Guide to Network Programming great! Now forget everything you've learned, my guide my rules. :lol:

Code: Select all

/**************************************************************\
/*                    Table of contents                       *\
/**************************************************************\
|                                                              |
| - Sugar cones                                                |
| - Fresh eggs                                                 |
| - One litre of milk                                          |
| - 5 pounds of cinnamon                                       |
| - Decaf                                                      |
| - That hawaian t-shirt I saw last time                       |
|                                                              |
|                                                              |
|                                                              |
|                                                              |
| Just kidding :P                                              |
|                                                              |
|                                                              |
|                                                              |
| >>> 1.  UDP vs TCP vs S.Korea                                |
|     -- 1.1 When to use TCP  (A)                              |
|     -- 1.2 When to use UDP  (A)                              |
|     -- 1.3 When to use both  (A)                             |
|     -- 1.4 What did Koreans taught us?  (A)                  |
|                                                              |
|                                                              |
| >>> 2.  Fixating over design patterns                        |
|     -- 2.1 Why should you care?  (A)                         |
|     -- 2.2 Why do others ignore design patterns  (A)         |
|     -- 2.3 Proactor vs Reactor  (A)                          |
|                                                              |
|                                                              |
| >>> 3.  A story of forbidden love and The Great Attack       |
|     -- 3.1 Episode 3: Settling old scores                    |
|     -- 3.2 Episode 2: NBIO and the Empire strike back!       |
|     -- 3.3 Episode 1: A new hope.                            |
|                                                              |
|                                                              |
| >>> 4.  Introduction to `polling`                            |
|     --  4.1 select, epoll, kqueue, /dev/poll  (A)            |
|     --  4.2 So, there are only 2 ways to poll per OS, right? |
|     --  4.3 What about non-blocking sockets?                 |
|                                                              |
|                                                              |
| >>> 5.  Staying out of sync                                  |
|     --  5.1 Introduction to IOCP and friends  (W)            |
|     --  5.2 Asynchronous I/O on unix  (U)                    |
|     --  5.3 Asynchronous I/O on bsd  (B)                     |
|                                                              |
|                                                              |
| >>> 6.  Sending and receiving data                           |
|     --  6.1 How should I do that?  (A)                       |
|     --  6.2 Managing your data  (A)                          |
|                                                              |
|                                                              |
| >>> 7.  When there's something strange in the neighbourhood  |
|         Who you gonna call?                                  |
|     --  7.1 fcntl, ioctl  (A)                                |
|     --  7.2 inet_xtoy and portability ghosts  (A)            |
|                                                              |
|                                                              |
 
Disclaimer: I'm not against external libraries in general, but I'm against most (libev,libuv,libiv,libov ... asio and poco). Only because they force certain things down your throat.
  • Boost::ASIO
    >> Forces you to install most of boost, which is a waste of time and space. The standalone version of ASIO isn't standalone, it still requires boost so no thanks.
  • POCO,libev,libuv
    >> They use `select` on windows. 'nuff said.
  • libev,libuv
    >> C syntax
  • 0mq
    >> Trying to abstract everything away is not always a good feature.
  • ACE Framework
    >> Severely outdated code.





Image

1. UDP vs TCP vs S.Korea
  • 1.1 When to use TCP
Before diving into when and why, let's see how TCP actually works.
TCP or Transmission Control Protocol is itself, you guessed it, a "Protocol" or "A way of communicating".

The word "control" isn't there by accident. TCP is working to "control" the flow of your data. Let's see how it works.

The client A sends a connection message to client B called (SYNchronize). Client B then has to respond that he got the
message and asks client A to be friends (SYN-ACKnowledgement). Then client A accepts the friend invitation sended by B.

Here's a more compact version.

Client A = 1
Client B = 2
1 ----(SYN)----> 2 // Hello!
1 <--(SYN-ACK)-- 2 // Hi there, lets be friends!
1 ----(ACK)----> 2 // Okay!
Then for each message called (DAT) the other end must respond with the "I got your message" message (ACK)
1 ----(DAT)---> 2 // Wanna go to the movies?
1 <---(ACK)---- 2 // I've got your message!

1 <---(DAT)---- 2 // I'd love to join you
1 ----(ACK)---> 2 // I've got your message! Awesome!
The same rules that apply to SYN, apply to FINish/FINalize.

Note that if one end doesn't respond with (ACK) the message will be sent again! Also notice that for each
packet we send, we're essentially waiting in case we have to send another, or another. The truth is that
we're also waiting for other stuff and all of these combined, result to poor performance if you're firing alot
of packets per second. Fortunately these problems can be circumvented but I'll cover that later.

Note: With TCP, packets are guaranteed to arrive in the order they were sent (LIFO)
- Thanks to CuteAlien for reminding me; i took it for granted that people actually read beej's guide :-D


So, when should I use TCP? Well ,normally , to time-critical applications such as
  1. Chatting
  2. Transactions
  3. Fights that are based on spell-chains as in WoW.
  4. RTS (RealTimeStrategy) games




In other words, if you want control, you must be willing to sacrifice performance. Though later on i'll teach you
how to minimize that performance loss ~



  • 1.2 When to use UDP
Well, most people agree that UDP should be used when one or two dropped packets is not a big deal. But what
do they mean by that? Shouldn't I care about the control flow?
The answer, my lads, is yes. You must care about the control flow. Because the attenuation of Player's 1 line
might be above average and the "one or two" dropped packets might become 100 or 200.

But that doesn't mean we should copy TCP right? Of course :P.

Let's see how UDP works.

Client A = 1
Client B = 2
1 (Sending a message) ------(MSG)-----> 2 (Reading a book) // Message lost because of TTL

// 2 hours later Client A didn't receive an answer and is pissed.

1 (Typing angrily) ------(MSG)-----> 2 (Waiting for a new message) // 1 says *&@$%#!$@#$ing #(*$%^*$@ ... insert Perl code here :D

1 (Waiting for a new message) <-----(MSG)------ 2 (Sending a message) // Why're you so mad bro?
What is TTL? TTL my lads is TimeToLive. It's a value specified by the OS (most of the times) and it tells how long one should keep
an unread packet before it's discarded.

So, applications like FPS shooters should use UDP! Yeah, kindof, keep reading!



  • 1.3 When to use both
To be short, if you have an FPS shooter with an active chatroom. Use UDP for position/rotation/world updates and TCP for the chatroom.
You could also use UDP for p/r/world updates and TCP for a custom "control" protocol that will be used to verify critical UDP packets.

>> Note that the last one doesn't make sense to me, none at all but I threw it in just because I've seen it implemented. <<



  • 1.4 What did Koreans taught us
What's with Koreans? What does this have to do with anything?

Well they didn't taught you anything (or not) explicitely but they taught me how the control flow works and a bunch of gotchas.
And as I pass the knowledge to you, they essentially taught us both something :P.


To be more specific I learned how to manage my structs from a Korean game that had it's server code leaked. ( I'm Mr.Illegal and that's how I roll )
Plus in the server code there were comments noting 2 things.

( That was back in 2004 there were was almost no MMORPG code to learn from ) :!:


So what were those comments about? It was a barely translateable message from the developers to system administrators telling them 2 things.
  1. Since they were using UDP, the lines attenuation should be kept as low as possible. Below 15dB.
  2. They should watch the servers SNR.
So, what does that mean? It means that if you're going with UDP you must have a good connection.

The line attenuation or noise margin is a value that tells us how much signal is lost because of background noise!

Here's a table. (Line Attenuation)

Code: Select all

/*
+====================================+
|    dB    |        Quality          |
+==========+=========================+
|  0 - 15  |  Excellent              |
+----------+-------------------- ----+
| 15 - 20  |  Very Good              |
+----------+-------------------------+
| 20 - 30  |  Works                  |
+----------+-------------------------+
| 40 - inf |  Terrible for a server  |
+----------+-------------------------+
*/
What about SNR?

SNR or SIGNAL to NOISE ratio or Noise margin is this (SIGNAL/NOISE). It's also measured in deciBel and the optimal values are.

Code: Select all

/*
+==============================================+
|    dB    |             Quality               |
+==========+===================================+
|  0 - 6   |   High speeds connection problems |
+----------+-----------------------------------+
|  6 - 12  |   Medium speeds fine connection   |
+----------+-----------------------------------+
| 12 - inf |   Slow speeds fine connection     |
+----------+-----------------------------------+
*/
Why should I care about my connection? Well, this is why!
Image












2. Fixating over design patterns
  • 2.1 Why should you care?
This section is a memorial to the countless argues I've had about design patterns. I've literally defended design patterns more
than anti-smoking habits or other stuff like that.
The main arguement was "I don't care about design patterns, I just send / receive data." (1)

The first time I saw that arguement, I thought the guy had gone nuts. But then I saw it again and again, it's like an ever growing conspiracy ~

Alright, but why should I care? Let's see, most people like bullets, i'll give 'em bullets.
  • Your whole server WILL be based around the design pattern you implement. After you choose, there's no going back!
So much for bulleTS, that's a bulleT ... Oh well, that's all I had :mrgreen:



  • 2.2 Why do others ignore design patterns?
Fixation is not a good thing, but awareness is. Most people are good at avoiding the former but as a consequence they fail at the latter!

Chosing a pattern is a step well ignored since the following concept has been stuck to peoples minds.

- The server is a reactor (waits for client messages)
- The client is a proactor (works in sync with the server)

Of course both can use whatever pattern you want. Anyway, let's dive into the whole acting scheme abit further ...



  • 2.3 Proactor vs Reactor


For those who're not good with prefixes, Proacting is a mechanism that acts before something; in this case, an event such as ( read, write )
And reacting is the opposite. It's a mechanism that acts after something!

Let's visualize them :P
A proactor
Do stuff
Read data
Do stuff
Read data
...
A reactor
Read data
Do stuff
Read data
Do stuff
...
For the sharp-eyed, the difference between the two is that their out of "phase".
In fact the phase difference is T/2. (Where T is the time required for a pair to complete their actions).

Alright, so they're essentially the same thing right? Yeah, pretty much! :lol:

So, when should I use them?

Proactor examples
  1. Add Nodes for each visible star in our sky and calculate the closest quad to the moon using gravity centers; for whatever reason :D
  2. A client noted that one node isn't a star but a plane
  3. Remove that node, recalculate, keep listening for client feedback
Reactor examples
  1. Wait for client action
  2. The client issued a "hit" command; damage the bosses health
  3. Wait for client action


So, what did part 2 taught us? Pick a pattern; stick with it.

Did I mention that you shouldn't pick the Reactor pattern on Windows. Oh wait; just don't pick Windows at all!












3. A story of forbidden love and The Great Attack
  • 3.1 Episode 3: Settling old scores
Alright lad, the whole point of this section is to make sure you understand that Asynchronous I/O != Non-Blocking I/O.

In order to do that, we'll need to see how they both work. Even though I already explained what AIO stands for, I'll try once more
just to make sure you've understood everything correctly.

AIO is a notification on completion model and that means:
- Issue a command.
- Wait 5 years / until the command has finished executing. The OS will inform you when that happens with a "notification"
Hence the "notification on completion".


Now let's see how Non-Blocking I/O works
- Issue a command.
- If it can execute without stalling so be it, if not continue anyway.
Which means, do not pause for whatever reason.

Alright, now we can move on to the next part!




  • 3.2 Episode 2: NBIO and the Empire strike back!
Alright, since we no longer confuse AIO with NBIO we can proceed to pinpoint the advantages of NBIO over SIO (Synchronous I/O).


Code: Select all

 
// My 2 penny worth non-nuclear reactor
 
Socket client = accept(...); // Blocking socket
for(;;)
{
    Data d = Recv(client);
    // create c based on d
    Send(client,c);
}
 
What would happen if the above code was used in a 1:1 scenario (1 thread per connection)?
The answer is `nothing special`, it would work as expected and it would be faster than the NBIO equivalent of this code.

What?? NBIO < SIO?? When talking about SIO, net gurus are like: Don't use SIO, SIO's bad, it slows you down, gives you cancer, burns your treehouse, eats your food, uses your teethbrush.
Wow, slow down fellow! Well, It's true that SIO is introducing alot of delays that are transparent to the code and hurt performance but, remember this:

In a 1 thread per connection scenario, no matter how appealing NBIO sounds, SIO will always outperform it.
Why?
1 word: Overhead.

In any other case (except AIO but I'll cover that later) go for NBIO.



  • 3.3 Episode 1: A new hope.
NBIO is neat but with it, serious headaches follow. Mainly because you have to constantly check i.e. if you sended/read everything, using handmade functions.
What if we could do all of this stuff in the background and instead of having custom functions, move the buffer and try again?

Fortunately for us, this is where Asynchronous I/O comes into play.

A well implemented AIO server would look like this:

Pseudocode; demonstration of AIO mechanism.

Code: Select all

 
enum{ RECV, SEND };
 
void AcceptThread()
{
    for(;;)
    {
        Socket client = accept(...);
 
        Assign(client);
 
        AsyncRead(client); // Issue the first Read
    }
}
 
void WorkerThread()
{
    Socket c;
    int io_type;
    char* data;
    size_t bytesTransferred, bytesLeft, bytesDone;
 
    for(;;)
    {
        GetQueuedCompletionStatus(c,io_type,data,bytesTransferred,bytesLeft,bytesDone);
 
        switch(io_type)
        {
            case SEND:
            {
                bytesDone += BytesTransferred;
                if( bytesLeft > bytesDone ) // move the buffer, issue AsyncSend again
 
                continue;
            }
            case RECV:
            {
                ProcessData(data,bytesTransferred); // Server logic goes here
                AsyncRead(c);
 
                continue;
            }
            default: continue;
        }
    }
}
 

So, let's say you spawn 10 workers; everytime an Async operation completes one of them will catch that here: `GetQueuedCompletionStatus`.
The rest are pretty self explanatory.

Also, do NOT mix NBIO with AIO! Think about it, it doesn't make any sense! Not that you'd see any difference, Async calls return immediately by default!

Read more regarding AIO in section 5.






Image
Some parts are not in the table of contents yet.


Part 1: Done!
Part 2: Done!

Part 3: Under revision!
Part 4: Halfway there!

Part 5:
Part 6:
Part 7:
Part 8:
Part 9:


Parts 1,2,3 are mostly theory. 4,5,6 will be code-oriented. 7,8,9 theory + code!
Last edited by Isomorphix on Fri Sep 06, 2013 2:06 pm, edited 55 times in total.
Isomorphix
Posts: 16
Joined: Fri Aug 16, 2013 5:08 pm

Re: [Teaser] Iso's awesome guide to networking

Post by Isomorphix »

Reserved.
Isomorphix
Posts: 16
Joined: Fri Aug 16, 2013 5:08 pm

Re: [Teaser] Iso's awesome guide to networking

Post by Isomorphix »

Reserved. Make me sticky, with a glue :wink:
Last edited by Isomorphix on Wed Aug 28, 2013 5:12 pm, edited 1 time in total.
Isomorphix
Posts: 16
Joined: Fri Aug 16, 2013 5:08 pm

Re: [Teaser] Iso's awesome guide to networking

Post by Isomorphix »

Reserved.
Isomorphix
Posts: 16
Joined: Fri Aug 16, 2013 5:08 pm

Re: [Teaser] Iso's awesome guide to networking

Post by Isomorphix »

Reserved. It's gonna be a lengthy guide :wink:
Isomorphix
Posts: 16
Joined: Fri Aug 16, 2013 5:08 pm

Re: [Teaser] Iso's awesome guide to networking

Post by Isomorphix »

Reserved. Judging from 1.1 it is going to be lengthier than I expected.
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: [Teaser] Iso's awesome guide to networking

Post by chronologicaldot »

Cool! Thanks for posting!

And thank you for offering doughnuts.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: [Teaser] Iso's awesome guide to networking

Post by mongoose7 »

Is this SPAM?
Isomorphix
Posts: 16
Joined: Fri Aug 16, 2013 5:08 pm

Re: [Teaser] Iso's awesome guide to networking

Post by Isomorphix »

chronologicaldot wrote:Cool! Thanks for posting!

And thank you for offering doughnuts.
My pleasure :P
mongoose7 wrote:Is this SPAM?
Nope, I reserved the first 6 posts because it's going to be a lengthy guide. There's a limit on how many characters a post can have!
Cube_
Posts: 1010
Joined: Mon Oct 24, 2011 10:03 pm
Location: 0x45 61 72 74 68 2c 20 69 6e 20 74 68 65 20 73 6f 6c 20 73 79 73 74 65 6d

Re: [28.75%] Iso's awesome guide to networking

Post by Cube_ »

hhhhhhooooly crap this seems like a good guide, bookmark'd and doughnut.
"this is not the bottleneck you are looking for"
Post Reply