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.