Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: I'm just confused  (Read 2962 times)

0 Members and 1 Guest are viewing this topic.

NameUser

  • Newbie
  • *
  • Posts: 30
    • View Profile
I'm just confused
« on: September 28, 2012, 03:23:37 am »
I've been working on adding netplay functionality to my game. Sadly however, due to me having 0% experience with networking code, I've been struggling quite a bit with this.

I've gotten the game and server to communicate, but I can't get certain things to work. For example, must I send all of the data I want to give to the client in one packet? How can it tell what the data is and thus what to use it for? That's not a huge deal for now, but once the game expands more, that's a LOT to be sending in a single packet. For another, I can't get my server to support multiple clients properly. I read up on Selectors in the 1.6 tutorial, but sadly that's too outdated. Several vital functions in that tutorial either no longer exist or are TCP only.

Can anyone give me a more up to date tutorial? Or some examples? Or at least answer those two issues?
« Last Edit: September 28, 2012, 03:32:37 am by NameUser »

Qix

  • Full Member
  • ***
  • Posts: 139
  • I am Qix!
    • View Profile
    • Natoga Technologies
Re: I'm just confused
« Reply #1 on: September 28, 2012, 04:16:41 am »
No you definitely don't have to send everything in the same packet. TCP has a 'handshake' type protocol which means the packets are guaranteed to reach you in perfect condition and should be in order. (UDP is arguably faster than TCP but works a little different and can't guarantee anything).

You can send multiple packets at the same time and the network/underlying networking code should transmit them accordingly.
~ Qix
Creator of Rippl Studio
Code: [Select]
<danharibo> iostream: I don't do enough drugs to think that's a good idea.

NameUser

  • Newbie
  • *
  • Posts: 30
    • View Profile
Re: I'm just confused
« Reply #2 on: September 28, 2012, 04:17:40 am »
I'm using UDP, not TCP.

Qix

  • Full Member
  • ***
  • Posts: 139
  • I am Qix!
    • View Profile
    • Natoga Technologies
Re: I'm just confused
« Reply #3 on: September 28, 2012, 04:36:27 am »
So with UDP, there is no guarantee the packets will be received in a timely fashion or at all, or more importantly in order. Generally they arrive correctly (not malformed) but again there is no guarantee.

Something else that should be noted with UDP vs. TCP is that TCP has a connection and a session, where as UDP does not have a connection. With UDP, you simply specify a destination address/port and send the packet off. If there is something listening on that port, then it will receive it. Otherwise, the packet will be ignored.

Generally you create a socket in the following order:
  • Start up any services if need be
  • Create the socket itself, passing information like IPv4/6, socket type (datagram <UDP> or stream <TCP>) and then the protocol (TCP vs UDP) (There are more options you can pass but these are the norm for simple networking applications)
  • Bind to a networking interface (generally a NIC card) - most generally used for listening as opposed to sending/connecting
  • (For TCP only) Connect/listen
  • (For TCP listeners only) Accept connections (this creates a whole new socket object, leaving the original 'server' socket intact for continued use)
  • Send/Recv
  • Disconnect/Shutdown/Close/cleanup/shutdown services (if any or all necessary)

So, for each send/recv on a UDP socket, you have to specify the ip address (`sf::IpAddress`) and port (0 - 65535; it's generally a good idea to keep them above port 1024 to avoid most port conflicts) to send the data to.

The cool thing about networking in C++ is the sending of structs outright. For instance, if you have

// Message struct
struct SOME_MESSAGE
{
int a;
int b;
float c;
char str[1024];
};

// Initialize a message
SOME_MESSAGE msg = {0};
msg.a = 5;
msg.b = 183478;
msg.c = 0.1337f;
strcpy(&msg.str[0], "Hello, world!");
 

You can send the msg object using

// Create the UDP socket and send the message data to 127.0.0.1:666
sf::UdpSocket sock;
sock.send(&msg, sizeof(SOME_MESSAGE), sf::IpAddress("127.0.0.1"), 666);
 

And receive it on the server, assuming you have the exact same struct definition, by doing:

// Create and bind the receiving socket on port 666
sf::UdpSocket sock;
sock.bind(666);

// Set up some variables to receive the data/information about the 'client'
size_t recvd = 0;
SOME_MESSAGE rmsg = {0};
sf::IpAddress recvIP;
unsigned short recvPort = 0;

// Receive the data
sock.receive(&rmsg, sizeof(SOME_MESSAGE), recvd, recvIP, recvPort);
 

(Note that this is all untested)

Now the above `rmsg` holds the data that was sent by `msg`, all in a neat little struct you can use. `recvd` is the number of actual bytes received by the operation (it should equal the size of the struct), `recvIP` and `recvPort` hold the IP/port address of the client that sent the data, respectively.

« Last Edit: September 28, 2012, 04:44:14 am by Qix »
~ Qix
Creator of Rippl Studio
Code: [Select]
<danharibo> iostream: I don't do enough drugs to think that's a good idea.

NameUser

  • Newbie
  • *
  • Posts: 30
    • View Profile
Re: I'm just confused
« Reply #4 on: September 28, 2012, 04:52:00 am »
  • Start up any services if need be
  • Bind to a networking interface (generally a NIC card) - most generally used for listening as opposed to sending/connecting

Don't understand what you mean with these.

Qix

  • Full Member
  • ***
  • Posts: 139
  • I am Qix!
    • View Profile
    • Natoga Technologies
Re: I'm just confused
« Reply #5 on: September 28, 2012, 05:04:06 am »
As for starting up services SFML takes care of it for you, but (for instance) on Windows, you usually need to call `WSAStartup`. Again, SFML takes care of these services so you don't have to worry about them.


As for binding, you need to specify where the data is coming from or where it is going to upon receiving data. With SFML, you need to say "hey, when applications want to send me stuff over the network, I'm expecting them to send it to port 666."

The best way I can explain it, albeit not exactly how it works, is that the binding 'filters' the incoming data so you only receive the data sent to a specific port.
~ Qix
Creator of Rippl Studio
Code: [Select]
<danharibo> iostream: I don't do enough drugs to think that's a good idea.