This is a tutorial I had written some time ago, that I would like to share here.
This subject can go by many names, networking, network programming, socket programming, internet programming, among others. For the course of this series, I will refer to it as socket programming.
In order to best understand how we can design and implement a network architecture into a game, we must first learn how networks actually work. First let us create a definition for the word Network.
Network: A hub of interconnected computers, in which each computer has the ability to talk to any other computer
The key thing about a network is the fact that they are connected, this gives the computers the ability to communicate in a universal way. What I mean by that is, the computers never have to change mediums of communication regardless of the data being sent. To give an example of a network would be really easy. You are reading this over a network, you are on the internet of course; and all the internet is, is a very large network.
Now that we know what a Network is, let us begin to examine how and what happens when computers “talk” to one another. We must now define a few new words.
Protocol: A way in which computers communicate; a set of “rules” of how the communication takes place.
Packet: A “holding” cell of information
Port: A medium in which computers pass packets through.
Now that we defined those three new words, let’s talk about each on a little more in-depth. Protocols act as a rule set in which computers must follow to pass information between each other, a good example of this, one in which everybody knows even if they don’t realize it, is the http protocol. The http protocol pretty much states how the computers will communicate, meaning what kind of information they can send and receive.
Packets are what hold this information that gets sent or received from various places. They are quite often comprised of various things, from different types of headers, and data, to maybe a packet that holds multiple headers.
The port is then the medium in which the packet is sent through, what port is used is usually determined by the protocol in use. So meaning, instead of having all the information pass in and out in one way, we can send information through various numbered ways. This helps prevent bottlenecks, and keeps everything separate, so you don’t have data crashing into each other as it comes into your computer.
Part 2
Ok now that we know what the basics of a network, we can begin to talk about how it plays into game networking. In order to begin discussing all of it, we first must define a new word.
Code:
Socket: A medium that we pass entire packets through, contains at least an IP Address and port
Sockets are the integral part of…you guessed it, socket programming, after all they are in the name! Sockets provide a means of transmission for us, as they allow us to connect to other computers, and have a way of listening for other computers to connect to us. Sockets contain at the very least an IP address that we connect to or are listening on, and a port in which we know where to exactly send the data we want. There are two main protocols which are very different for sockets, which we will define and then go into detail.
Code:
TCP: Transmission Control Protocol, one of the main rule sets that we can use to send packets through sockets.
TCP is known as a connection based protocol, meaning for every socket we have, we must connect to a listener socket; which is waiting for us. Now this is good because this allows us to keep track of all the stuff we are sending and receiving, as well as for the server to keep track of all its clients. This is the most commonly used protocol for game networking, the other is used at times, but this is the main one. This is for a few reasons.
Code:
IMPORTANT INFORMATION!
1) TCP uses a connection based system, allowing programmers to easily track and use the various connected sockets.
2) TCP’s rule set states that ALL packets will arrive IN ORDER and COMPLETE
3) TCP allows easy sending and receiving of data
These may make it seem like TCP is the greatest thing, and that there shouldn’t be a second protocol, that TCP handles all the business. Well it does…for a price; you see TCP checks everything to make sure that it is all in order and complete, and if it isn’t…well…then it has to request a new packet. All of this costs lots of time and performance, so a much faster protocol was created to deal with some of these problems.
The second socket protocol is defined as follows:
Code:
UDP: User Datagram Protocol, a connectionless protocol, utilizing speed and performance to deliver packets.
Yes you read it right, UDP uses a connectionless approach. What this means is, instead of connecting to a client or server; we automatically assume we will have access, and simply just send the information along.
UDP uses a type of packet that we will define.
Code:
Datagram: a packet send from an “unreliable” source
You are probably asking, “what do you mean unreliable?” well it is just that, the reason is in the word. UDP is unreliable, meaning that packets cannot be guaranteed to get there complete, or even at all. As sometimes we may lose datagram, or it may arrive incomplete. So why use it at all if it is unreliable? The answer is simple…performance.
You see, since we are not doing all those costly checks to make sure that the packet is complete, or if it arrived at all, or if it even arrived in order, we gain something…Performance. This is the reason why people use the UDP protocol. So let us go over some of the information that is here.
Code:
IMPORTANT INFORMATION!
1) UDP uses datagrams, giving it a connectionless transmission layer
2) UDP is considered “unreliable” due to there being no checks on datagrams
3) UDP has better performance than the TCP protocol, because it is “unreliable”
Protocol TCP UDP
Connection Type Connection based Connection-less
Reliability Packets arrive complete Packets may not arrive
Ordering As sent May arrive not in order
Weight Heavyweight Lightweight
Packet Type Byte Streams Datagrams
Part 3
Now that we understand the basics of what a network is, what sockets are, and we have information about two of the most popular transmission protocols (TCP and UDP). We can now begin to take a look at a basic implementation of Sockets.
Code:
ADVANCED WARNING
I will ONLY be covering Win32 socket stuff, much later in the series I will go over some multi-platform libraries like Boost, but until then, I will only talk about Winsock
Winsock comes in two flavors, the 1.1 edition, and the 2.0 edition. For this series, we will use the 2.0 edition. Not only because it is newer, but it also supports newer protocols, and is simpler to use.
This part will outline some of the high level functions that we will be using in the creation of our network structure.
Starting off, we need to know what file we need to include so we can use all this socket goodness.
Code:
#include <winsock2.h>
there we are, as simple as that.
In Winsock we have a struct called WSAData, that is our basic implementation of the Winsock architecture.
WSAData looks like this:
Code:
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
#ifdef _WIN64
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
#else
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
#endif
Most of this you don’t need to worry about at all, and I have only shown it here, to show you what it looks like.
In the beginning of our program, we will want to create an object of type WSAData, for those who better understand by seeing it means this.
where the variable data can obviously be anything you want it to be.
After we make our object, we will want to make a call to Winsock’s startup function.
Code:
WSAStartup(__in WORD wVersionRequested, __out LPWSADATA lpWSAData )
Now don’t let that confusing looking argument list get to you, it is actually really simple.
The first argument it asks for is simply the version of winsock you want to use, it could be 1.1, 2.0, or the even newer 2.2! The second argument simply asks for our WSAData that we created the line before. An example of this call would be.
Code:
WSAStartup(MAKEWORD(2,0), &data)
What is that MAKEWORD!? Relax, all it does is turn the two numbers we give it into a WORD datatype. Also im sure you noticed the big & infront of data, meaning yes we must pass the WSAData object in by reference! If you do it any other way, you WILL get compile errors
Now that we know that, lets dive in just a bit further with WSAStartup, you see it has a return type of int, meaning it will give us a number based on what has happened. WSAStartup will ALWAYS return a value of 0 (zero) on a successful startup, it will return a different value based on the error. For now all you need to worry about is if it returned a 0 or not.
So let’s see everything in action!
Code:
#include <winsock2.h>
#include <iostream>
int main()
{
WSAData data;
if(WSAStartup(MAKEWORD(2,0), &data) == 0)
std::cout << “Winsock started successfully!”
else
{
std::cout << “Winsock failed to start!”
return 0;
}
WSACleanup();
}
oh? You saw that WSACleanup() eh? Well its job shouldn’t be a mystery, after all it is in the name.
Code:
IMPORTANT INFORMATION
You MUST call WSACleanup() at the end of your program if you are using Winsock
We will begin discussing the SOCKET data type in part 4, along with the basics of sending and receiving information.