Tag Archives: networking

[SDL2 – Part 13] Multiplayer – TCP

Continuing where we left of…


Last time we left off after having taken a look at UDP connections. But, as we saw, UDP connections have several issues :

  • No delivery guarantee
  • Packages might not arrive in the same order they were sent

So how do we solve these issues? By creating an actual connection. A TCP connection that is.

TCP connections


As mentioned in the previous post, UDP connections aren’t connections at all. It’s basically just two parts sending data back and forth between them. TCP connections, however, are proper connections. This means we know the following :

  • Both parts tries to keep the connection alive
  • Both parts have received everything the other part has sent
  • Every package has been received in order

These points requires two different mechanisms, so let’s look at the one by one.

How TCP works


In order to have a connection, both parts have to agree on it. This is different from UDP connection because in UDP connections we just send the data without bothering about actual connections. So how do we set up the TCP connection? By using a technique called three-way handshake

The three-way handshake


The process of establishing a TCP connections requires three different steps:

  • Part 1 contacts part 2 and asks to start a connection
  • Part 2 replies and either says OK, or declines
    • If part 2 declines, the process stops here
  • Part 1 replies back, to confirm that he’s received part 2’s request
  • Now the actual connection is started and we can send data

The third step might seem kinda unnecessary, but remember that any packages can get lost. And so if part 2 doesn’t get the answer from part 1, part 2 doesn’t know whether part 1 is still there. Part 1 might have lost the connection or wished to stop it altogether. We can compare this to starting a phone call :

  1. Part 1 calls part 2
  2. Part 2 picks up and says hello
  3. Part 1 says hello back

After the last step, the conversation is started. All of these step are necessary for us to know there is an actual conversation. Skipping one of them might make you think something is wrong. For instance, if part 2 doesn’t say ‘hello’, you might think there is something wrong with the connection.

Dealing with the UDP issues


The major flaw of UDP is that it doesn’t deal with loss of packages. And another issue is that we don’t know if we’re getting the correct package at the correct time. Potentially we can get every package in the wrong order. Which could lead to everything from glitchy gameplay to crashes. So let’s look at the mechanics that makes TCP connections able to give their guarantees :

ACK numbers


In TCP every package gets a unique number. This is basically just a counter so the first package gets the number 0, next one 1 and so on…

This number is then sent back from the recipient to confirm that “okay, so now I have every package up to this package” ( I will refer to the confirmation as ACK numbers.) So when we get an ACK for the last paackage we sent, we know that the other part has received everything we have sent so far. This means we don’t have to worry about any of the packages having been lost.

But say the receiver misses a package in the middle? For example, what if the receiver gets package 1,2,4, but not 3? The receiver will look at the ACK numbers and think “huh… I’m missing a package here.” And will only send ACK 2 back. At this point, your application might get package 1 and 2, but not 4, since it’s out of order.

Flow of TCP


Let’s look at an example to see how the TCP might handle loss of packages.

  1. Sender sends package 1,2,3,4
  2. Receiver receives package 1
    • Your application receives package 1
    • Send ACK 1 all good so far!
  3. Receiver receives package 2 and 4
    • Uh oh! Where’s package 3?
  4. Sender receives ACK 2
  5. Sender waits a while before resending package 3 and 4
    • It sends package 4, which the receiver already has, because it only got ACK2
  6. Receiver receives package 3
    • Now your application will get the last two packages ( 3 and 4 )
    • Receiver sends ACK 4
  7. Sender receives ACK 4
  8. Receiver receives package 3, again!
    • The original package 3 was just delayed get it again.
    • Since we already have these packages, it’ll get discarded

Now the receiver has got all 4 packages and all is fine and dandy. But if you study the example, you see that in our case the sender has to resend 2 packages ( 3 and 4), while the receiver in reality only needed one ( 3 ) And in addition, we got package 3 twice. But even though we got package 4 early, it wasn’t sent to our application before we got package 3 because TCP we receive everything in order. This is one of the major drawback of TCP ; there can be lots of delays and re-sending of packages.

TCP send rate


A final issue about TCP performance is how it regulates package sending. TCP can send several packages at any time. The basic idea is that every time every package is sent successfully and in time, it’ll send more packages the next time.

So the first time, it might only send 2 packages the first time. But if it gets ACK for all those three in a given time, it might send 4 the next time. Then maybe 8 and keep increasing it until it doesn’t get an ACK for all packages on time. When that happens, it’ll send less packages the next time. Let’s look at a simple example :

  1. Send 2 packages
    • Receive ACK for both packages
  2. Send 4 packages
    • Receive ACK for all packages
  3. Send 8 packages
    • Receive ACK for only 5 packages
    • We’re missing 3 packages! Maybe this was too many packages? Try sending less…
  4. Send 6 packages

As you can see, TCP will try its best to keep sending the maximum number of packages without having to resend anything.

Complexity of TCP


Although TCP is quite old ( more than 30 years old, ) it’s really complicated. There are a lot of different mechanisms involved to deal with anything that might happen. Not only do they handle the cases we’ve seen, but it also, as we saw, needs to control the speed for optimal performance.

I have purposely simplified it because its nice to have a basic understanding of how TCP works as this might help you to choose whether you should use UDP or TCP

The two different parts of TCP connections


Since TCP connection are actual connections, there needs to be a central part ( server ) that the others ( clients ) connect to. I’ll briefly discuss servers and clients, and what their roles are when it comes to TCP

Server


The server is the part that all the clients will connect to. So the server will always be listening for new connection and accepting them as they come. The server will be accepting connections from any client, so we don’t specify IPs on their server side ( ,ore on this later. ) We will only specify the port to listen to.

Client


The client tries to connect to the server. It needs to know both the IP and port of the server before it can try to connect to the server. The server doesn’t know anything about the client until it tries to connect to the server.

When the server accepts the client, the connection is established. At this point in time, the server also has a connection to that client specifically. We’ll see this later.

Note that these are just different types of connection, not necessarily different computers. A computer can have any number of server and / or client connections.

Time for some code


So now that we have all the technical information about TCP is out of the way, we can start setting up a TCP connection of our own. As you might expect, the source code for TCP is a bit more involved than the UDP one.

This part relies on code from my previous post. If something is unclear, you can go back and read that part if you want more information. I have also added links to the documentation in the headers.

SDLNet_ResolveHost


Just like with UDP, we need to ask SDL net to get correct the correct representation ( because of different endianness). The function is the same ( but it is used in a different way for servers, so do read on)

Parameters :

  • IPaddress* address – a pointer to an allocated / created IPAdress.
  • const char* hostIP address to send to ( xxx.xxx.xxx.xxx )
  • Uint16 port – the port number to send to

Return value

The int value 0 on success, otherwise -1. In this case, address.host will be INADDR_NONE. This can happen if the address is invalid or leads to nowhere.

But there is a slight difference in how it’s used. Since TCP connections are actual connections it has both a server and a client part :

Server

The server part needs to be listening for IPs that are trying to connect. So we’re not really resolving a host this time. We’re just preparing the IPaddress for the next step.

So what we do is that we simply use null as the IP. This tells SDL_net that we don’t want to use this IPaddress to connect to a host, but rather just listen for other connections. SDL_net does this by setting the IP to INADDR_NONE. This comes into play in the next step ( SDLNet_TCP_Open)

Client

For clients, this function is used more or less exactly like in the previous part ; it’ll prepare the IPaddress with the information we supply.

Of course, the port on both the server and client side has to be the same.

Note: no connections has been initiated yet, we’ve just asked SDL to prepare the port and IP address for us.

TCPSocket


This is a new type. It represents a TCP connection. We’ll use it just like UDPSocket but of course this time it represents a TCP connection instead of a UDP connection.

SDLNet_TCP_Open


Now that we have an IPadress correctly set up, we can try to connect to a host. This is done by the function SDLNet_TCP_Open

Here is the function signature.

Parameters :

  • IPaddress *ip – an IPaddress* contaning the IP and port we want to connect to. We’ll use the one we got from SDLNet_ResolveHost

Return:

  • For clients : a TCPsocket to the server, which can be used for sending and receiving data
  • For servers : a TCPsocket used for listening for new clients trying to connect

This function will try to open a connection. But just like with SDLNet_ResolveHost, there are two different cases here

Server


Above we saw that if we call SDLNet_ResolveHost with null as the IP, SDL_net will set the IP of the to INADDR_NONE. This means we will be listening for connections, rather than trying to connect. This is because, as a server, we don’t actively try to connect to another host ( we just accept connections ), so we don’t know about any IP address yet.

What this function does in this case, is that it tries to open the port for listening.

Client


For clients, this works much like for UDP : we try to connect to the server with the given IP and port

At this point, the client is connected to the server, and now they can communicated. This is a little different from how it works in UDP so let’s start by looking at how the communcation can be done in TCP

A quick example


Before we jump into the next part, let’s have a quick look at an example of how to use these two functions. These two functions are the initialization part of the TCP code. Since these steps are slightly different form client to server, I’ll cover them separately.

Server


Simply set up the IP address and use it to open a port for listening :

Client


Simply set up the IP address and try to connect to server with that IPaddress :

The job of the client


The clients are the parts you’ll be dealing with they most. A client communicates with other clients. This is more or less just like in UDP, but there are som differences.

SDLNet_TCP_Send


Sending data using TCP is done using a slightly different function from that of UDP :

Parameters :

  • TCPsocket sock – the TCPsocket* on which to send the data
  • const void *data – the data to send
  • int len – the length of the data ( in bytes )

This function is quite straight ahead. The only thing to note is the void*. The type void* is something that is widely used in C but not so much in C++. It’s basically a pointer to anything. So the data can be just about any form of data. This requires a bit of low-level C “hacking” to get right.

Return:

The number of bytes that was sent. If this is less than the size of the data we tried to send ( or the len parameter, ) an error has occured. This error could be the client disconnecting or a network error.

Using this function correctly is tricky, in a similar way to UDP. Let’s look at a possible way to implement it ;

SDLNet_TCP_Recv


Receiving data using TCP is also done using a slightly different function from that of UDP :

Parameters :

  • TCPsocket sock – the TCPsocket* on which to recv the data from
  • const void *data – the data to receive
  • int maxlen – the maximum data to receive

Return:

The number of data received. If this is less than 0, an error has occured.

And since this is C ( and not C++ ) we need to allocate a decent sized buffer in advance ( this is the void *date part. It’ll have the same size as maxlen. The setting of the buffer involves a little C-style trickery.

Let’s look at an example :

The job of the server


So now we have a TCPsocket that listens to the port we specified. And now we can try to accept new connections. For now, we’ll try to accept connections right out of the blue. But later we’ll look out how to check for clients trying to connect. Anyways ; here is the method we need:

SDLNet_TCP_Accept


This is the essentially the accept part of the three-way handshake. The client has tried to connect to us and we need to accept it before the connection is established. This function does exactly what you might expect : it accepts an incoming TCP connection, informs the client and thus establishing the connection.

Parameters :

  • TCPsocket *server – the TCPsocket* we use for listening for new connections. This is the TCPConnection we created using SDLNet_TCP_Open.

Return :

A different TCPsocket this TCPsocket does represent a connection to a specific client. If it’s valid, it means a connection has been established. If it’s null it means no connection was established. This can mean that there was an error. But it can also mean that there was no clients trying to connect.

This function might lead to some confusion as there are two TCPsockets, but remember :

The first one ( the parameter we supply ) is ther server TCPsocket. This is not connected to any client, we just need it to be able to listen for new connection. We create this TCPSocket by callling SDLNet_TCP_Open

The second TCPsocket is for a specific client.We create this TCPSocket by callling SDLNet_TCP_Accept. When it’s created, it can be used exaclty like the TCPsockets created on the client side. ( As I talked about in the cleint part of SDLNet_TCP_Open )

Dealing with SDLNet_TCP_Recv


There is a major issue with the receive function. It blocks. This means the function waits until it has received something. Actually, according to the documentation, it’ll wait til it has received exactly maxlen bytes and then set those in the void* data. But from what I’ve found, this isn’t 100% true.

What I have found, is that the function will block. But only until it has received something ( at most maxlen bytes. ) So, in other words, it waits til it has received something, no matter how little or much it is. But even though this is better than waiting for maxlen bytes, the fact that it blocks is still an issue we’ll need to solve.

SDLNet_TCP_Recv will also join together messages if it can. So say client 1 sends

“Hello”

and

“World”

in two separate messages, SDLnet can join them together so that what client 2 gets is

“HelloWorld”

in one message.

This can ( and probably will ) happen if buffer size is large enough.

Or, if the buffer size is too small one call might only get part of the data. So if client 1 sends :

“HelloWorld”

But client 2 has the buffer size set to 6, it’ll get

“HelloW”

The first time client 2 calls SDLNet_TCP_Recv. And

“orld”

The second time it calls SDLNet_TCP_Recv

That means there are two issues to fix : the fact that it blocks and the fact that we might not receive everything with one call to SDLNet_TCP_Recv.

SDLNet_SocketSet


To solve this, we can check if something has happened on a collection of TCPsockets, this includes someone connecting, disconnecting or receiving data.

We can use a SDLNet_SocketSet to solve this. Think of it as simply a set of sockets. We’ll be using it for storing and checking TCPsockets to see if there is any activity. A SDLNet_SocketSet can contain any number of TCPSockets. Those can be both server and client connections.

SDLNet_TCP_AddSocket


This is a really simple function for adding a socket to a SDLNet_SocketSet. It also exists for UDP, but we’ll be using the TCP version, of course.

Parameters :

  • SDLNet_SocketSet *set – the SDLNet_SocketSet we want to add the TCPsocket to
  • TCPsocket *sock – the TCPsocket we want to add to the SDLNet_SocketSet

Return :

The number of TCPsockets in the SDLNet_SocketSet on success. Or -1 on failure.

SDLNet_CheckSockets


Now that we’ve added sockets to the SDLNet_SocketSet, we can use the SDLNet_CheckSockets function to check for activity. “Activity” in this case basically means that something has happened. This can either mean we have received data, that someone has disconnected or that there is an error.

Parameters :

  • SDLNet_SocketSet *set – the SDLNet_SocketSet we want to check for activity
  • Uint32 timeout – a variable stating how long ( in milliseconds ) we want to wait for activity. We can wait anything between 0 milliseconds and… well anything up to 49 days.

Return :

The number of TCPsockets in the SDLNet_SocketSet with activity on success. Or -1 if either theSDLNet_SocketSet is empty or there was an error.

SDLNet_SocketReady


After we’ve called SDLNet_CheckSockets, we can use this function to check whether a particular TCPSocket has been marked as active. This function should be called on a socket on a SDLNet_SocketSet after code>SDLNet_CheckSockets has been called on the SocketSet that holds that TCPSocket.

Parameters :

  • TCPSocket *socket – the TCPSocket we want to check for activity

Return :

Count of TCPSockets with activity

In other words ; we use SDLNet_CheckSockets to see if any of the TCPSockets in a SDLNet_SocketSet has any activity. If so, we can call SDLNet_SocketReady on each of the SDLNet_SocketSets in that SDLNet_SocketSet to see if that TCPSocket in particular has any activity.

Examples

Now let’s look at how you could implement an update function that checks for activity. They’ll be different for server and client connections since client connections checks for incoming messages and disconnections. While on the server side we’ll simply check for clients trying to connect.

Client side example


As I mentioned above, on the client side we need to check for connections and incomming messages. Here is a way to do that :

A problem that arises here, is that calling code>SDLNet_CheckSockets kind of sets the TCPSocket back to “inactive” when you call it. Even if there is several messages waiting to be read.

So when you have called ReadMessage(), you have no way of knowing if it has any more data. Calling it again, would mean calling SDLNet_TCP_Recv again which could block until the other client sent more data.

This is an issue lots of tutorials that I’ve seen has. But there is a solution that doesn’t block ; we just need to call SDLNet_CheckSockets again. So just add this to the bottom of the previous function

Server side example


On the server side, we need to check for clients trying to connect. This is fortunately a little bit simpler than what we had to do on the client side. Here is the code :

I think that’s all for now. You can find a working implementation

here.

Conclusion


Setting up a TCP connection using SDL_Net is quite tricky. Lots of tutorials out there just briefly discuss the topic without going into much detail about the different functions. Hopefully this post has helped you get a better view of the different parts of SDL_net ( I sure did writing it! ) I might also post a third networking post about an even better way of doing network communication using both UDP and TCP for maximum performance.

I’m also really glad to finally have finished and published a new post. I know it’s been a long time since last time, but I’ve been a bit busy at work and haven’t really had the time or energy. But I feel some of my energy is back. And getting positive feedback is always amazing, they help me keep going. So thanks to everyone who’s commented! : )

(Semi) Final code :

Working implementation of TCP connections ( NOTE : work in progress! )

Github page


Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com
Share

[SDL2 Part – 12 ] Multiplayer

Introduction


A huge aspect of game programming is multiplayer. A huge share of all the popular video games today support internet in sme ways. But this introduces several new challanges. Both in the communciation over internet itself but also in what data to send, how to react to data and how to make everything synchronized. This is going to be a sub series in itself starting off with how to do the actual communication.

Packages


When you’re sending something over the Internet, it’ll get split into quite small packages. Each of these packages are usually a few kilobytes or smaller. There are actually several types of packages which get wrapped in each other. I won’t get into the details of this, but what we need to know is that there are several types of packets and they get wrapped in each other.

One of the basic packet types is the IP ( Internet Protocol ) packet. You can look at this as the package that leaves our computer and is sent out on the Internet. Every package that is sent across the Internet is of this type.

IP package

We won’t go into the details of each of these fields, the image is there just to show you how it looks. I might go into the details on a later point in time, but that is a big topic and we don’t really need to know all of that in order to do multiplayer.

The package is then sent out on the Internet and will eventually find its way to its destination PC. This is similar to sending a letter. You put the letter inside an envelope and write the destination address on it. Then the mail carrier will take care of the rest.

Actually, that isn’t entirely true because there is another step before the package leaves your computer; we need a protocol.

Protocols


Above we saw an example of in IP package.

So now that we know about packages, the next topic is protocol. A protocol is basically a set of rules about how the two parts should communicate. Most important to us, these rules dictate how to detect package loss and how to deal with them.

Why do we need protocols?


Most of the times when you send something, everything goes fine and the recipient gets the data packages he need. But things can go wrong. Let’s take an example.

Say we have sent our letter to someone. But on it’s way, the letter gets lost. But how can we know? The mail carrier doesn’t know that the letter is lost. The recipient doesn’t know you’ve sent the letter and you yourself is assuming the letter arrived at its destination without any issues.

The exact same thing could happen on the Internet ; packages can get lost, and none will know. So how can the problem be avoided? This is where protocols come in!

There are two protocols, we’ll cover, TCP and UDP. This time, I’ll only cover UDP. I’ll cover the other one, TCP, in a later post.

UDP


The most basic of the protocols we’ll look at is UDP ( User Datagram Protocol. ) Actually, UDP is so basic, there is no rules about how to deal with package loss. You have to handle that yourself.

Another issue is that there is no guarantee that the packages will be received in order. So you could get packages 1,2,3 as 3,2,1 or 3,1,2 or 2,3,1 etc.. And that’s if you do get all packages. Needless to say, using UDP can cause lots of problems. But its’ simple so we’ll start with it.

UDP is generally used for performance or simplicity reasons :

  • Video streaming
    • If a package is lost, this is just a tiny piece of the stream data and you might not even notive it
  • In cases where you just want to send a state to the server
    • Like using ping where you just get an echo back
    • If you don’t get a message back, you can retry again and again, or report an error
  • Games
    • For reducing lag
    • This means they have their own way of dealing with package loss

Addressing on the internet


On the Internet, there are two units used for addressing, the IP address and the port number. We need both of these to communicate over the Internet.

IP adress


The IP address is used to address computer. Every unit on the Internet has an IP address that refers to that unit. You can look at it as the address of a house. So when you send a letter to someone in a house, you write the address to that house. When you send a packet to a computer, you send a packet to that IP address.

Port numbers


Port numbers are used to distinguish between connections. Each connection has a separate port number tied to it. If we didn’t have port numbers, all data would go into a large buffer and you’d have no idea which of these datas where yours.

So if an IP adress refers to a house, a port could be looked at as a name.

When you set up a connection, you need both of these an IP address and a port number. Actually you need two of both since the receiver needs to know who sent the package so that it needs to know who to reply to. So all in all, we need two IPs ( out IP and destination IP ) and two port numbers ( our port numbers, destination port numbers. )

So basically, you neeed :

  • Your own IP adress and port number
  • The recipients IP address and port number

Setting up the connection


Actually, UDP is not really a connection, it’s just two parts sending data back and fort. But both parts still needs to know both IP and port number of each other. And it is common and more practical to think about it as an actual connection.

There are two roles in a UDP “connection”.

  • A client
    • Tries to connect to a server
  • A server
    • Waits for a connection from a client

So the procedure for a “connection” will be something like this

  • Server with ip 123.123.123.123 waits for connection, listening to port 123
  • Client sends a packet to 123.123.123.123, port number 123
  • Server stores IP and port number for client
  • Server and client now knows both port number and IP of each other
  • Now the server and client can now send data back and forth

Sockets


The final part we need to cover about connections are sockets. A socket is a combination of IP address and ports that is unique on every PC for every connection. It consists of the following :

  • IP and port of the client side of the connection
  • IP and port of our the remote part of the connection
    • This part is mostly used for TCP connections, we won’t use it
  • Type of connection ( UDP, TCP, etc… )

We’ll be using sockets as a unit to keep track of a connection. You can look at scokets to the sockets you plug your electric devices to. Following that analogy, the wire would be the connection ( network cable ). So, in essence, it’s what connects your application to the Internet.


I realize this all might be a lot of information and hard to wrap your hand around it all, but it’ll get clearer when we put it to use.

SLD_net


Now that we know a tiny bit about UDP connections, let’s try to set up one ourselves. For that purpose, we need the SDL_net library. It is capable of setting up and maintaining both UDP and TCP connections. Since UDP connections are way simpler, we’ll only cover that for now.

Networking is, just like text rendering and .png loading, a separate part of SDL called SDL_net. We install it the exact same way as before :

Installation


Installing SDL2_net is done exactly like SDL2_image. Just replace SDL2_image with SDL2_net

Here’s the short version :

Linux


For Linux you can use need to install -lSDL2_net or -libSDL2_net or -SDL2_net ( the actual name might be different in different distributions. )

The linker flag is -lSDL2_net

The process is more or less identical to that of setting up SDL2_image.

If you can’t find SDL2_net in any repositories and it’s not installed by default, you might have to compile it yourself. For more information, see my blog post about setting up SDL2.

Windows


Similar to setting up SDL2 base.

The difference is that you have to download the development files for SDL2_net

And similarly add SDL2_net.lib to library includes and add SDL2_net.lib to the library flags ( where you previously added SDL2_image.lib )

And with that, it should work.

Mac


See the first part of my tutorial. Just install SDL2_net instead of SDL2

Using SDL_net to set up a connection


Setting up a connection with SDL_net is a bit more complicated than what we’ve previously seen. This is because there are a few steps, the code will be very C ( not C++ ) and there are some buffers ( raw arrays ) we need to keep track off.

We’ll be cutting out all GUI because we simply don’t need it. It will make our code shorter and it’ll be easier to display the results.

Structures of SDL_net


SDL_net contains two parts we need for out UDP connection. Let’s start with the simplest, IPAddress.

IPAdress


A simple struct with the following fields :

  • uint_32_t hostIP v4 address
  • uint16_t host – protocol port

It is used for keeping IP and port number together. Some functins takes this as one of the parameters.

UDPSocket


A pointer to a data type that holds to a pointer. Since it a pointer, it can be NULL, in which case there is no connection and we can’t send data back and forth.

UDPpacket


Our data packet. Contains the data we are sending back and forth along with some other information.

  • int channel
    • The src/dst channel of the packet
    • We won’t be using this
  • Uint8 *data
    • The packet data we’re sending
    • Can be of any length
  • int len
    • The length of the packet data
    • Used to find the end of the data in the data pointer
  • int maxlen
    • The max size of the data buffer
    • Always as large or larger than len
    • Only used for data package creation on the senders side
  • int status
    • Packet status after sending
    • Number of data sent
    • -1 on failure
  • IPaddress address
    • the source/dest address of apacket
    • For received packages this is the IP / port of the remote part.
    • For sent packages this is the IP / port to send to.

The various fields of a UDP packet is set with various function used for sending and receiving data. It might seem confusing right now, but it’ll get clearer once we get into the actual code.

Functions of SDL_net


SDLNet_Init


This function is just like SDL_Init and TTF_Init ; it initializes the SDL_net

SDLNet_UDP_Open


This function is used for creating a socket which we will use later to send data.

Parameters :

  • Uint16 port – the port we want to use. If you use 0, SDL_Net will assign a port for you.

Return value :

A valid UDPsocket, NULL on error. Remember that UDPSocket is a pointer.

As we saw earlier, UDP isn’t actually a connection. All we are doing is sending data back and forth. And all we need to do that is a socket. Now that we’ve opened this socket, we can start dealing with packages.

SDLNet_ResolveHost


As stated before, we need an IP address and port number in order to send data. The problem is that there are several ways to represent IP addresses and port numbers. The difference between them is the order in which the they are converted to binary. These orders are refereed to as little endian and big endian I won’t dive more into this, but you can read about it here.

The issue is that different system use different endian. So we need a uniform way of setting the IP address and port number. This is where SDLNet_ResolveHost comes in. What it does, is that it sets the name values of an IPAdress for us so we don’t have to think about endians at all.

Parameters :

  • IPaddress* address – a pointer to an IPAdress. Needs to be allocated / created in advance. ( In our case, we’ll use a variable and not a pointer so we don’t have to worry about this. )
  • const char* hostIP address to send to ( xxx.xxx.xxx.xxx )
  • Uint16 port – the port number to send to

Return value :

0 on success, otherwise -1. In this case, address.host will be INNADDR_NONE. This can happen if the address is invalid or leads to nowhere

SDLNet_AllocPacket


Allocates a UDP_Packet and returns a pointer to it.

Parameters :

  • int size – size of the packet in bytes. 0 is invalid.

Return value :

A valid pointer to UDPpacket, NULL on error ( such as out of memory )

The size of the packet determines how much data we get every time. It’ll never be more than this size, but it can be less. You can also expect that some packages gets mfSerged or split up into different segments. This is something we’ll need to handle.

After allocation space for a packet, we can finally fill that packet up with something. Which is kinda the point of this ordeal.

SDLNet_UDP_Send


Sends a UDPpacket

Parameters :

  • UDPsocket sock – Our socket to send data from ( the one we created with SDLNet_UDP_Open )
  • int channel – We’ll completely ignore this parameter and just set it to -1 ( all channels )
  • UDPpacket* packet – the data we want to send ( finally! )

Return value :

The number of destinations the packet was sent to. In our case, this will be 1. But it could be more. Because of this 0 is returned on errors. Anything higher than 0 means partial success ( since we were able to send to at least one destination. )

In our case, the function should always return 1 but I find it better to just check for 0.

SDLNet_AllocPacket


Now that we know how to send data, we also need to know how to recieve them.

Parameters :

  • UDPsocket sock – Our socket to receive data from ( the one we created with SDLNet_UDP_Open> )
  • UDPpacket* packet – the data we received

Return value :

The int value 1 when a packet is received, 0 when no packets where received, and -1 on errors.

Example


To make it simpler to use SDL_Net, I’ve made a helper class that takes care of everything. You’ll find an example at how to use it below.

Compile


To compile it on Linux or Mac. Simply run :

clang++ UDPExample.cpp -std=c++11 -lSDL2_net -o UDPTest

Starting the example


To use the example, you need two instance of the application. So start up two instances of it.

You’ll be asked to enter local IP. This is the IP of the computer you are sitting on. You can use 127.0.0.1 which simply means “this computer”. You can do this in both instances. You’ll also be asked to enter a local port and remote port. These needs to be opposite on the two instances ; the local port of the first one, needs to be the remote port of the other. This is because we need to know where to send it to and where to listen for data on.

Instance 1


Instance 2


( notice the difference in local and remote port on the two instances. )

Using the example


After inserting IP and port data, you’ll be presented with a simple menu :

Nothing will happen before you do one of the three options. And if your message doesn’t show up on the other instance, make sure you’ve entered ‘2’

And now you should be able to set up connections. Feel free to use the UDPConnection struct as you like.


Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com
Share