I've looked at tutorials and many other places on how to do this however I'm still having trouble getting this to work. Interestingly enough I did find a tutorial (which is where I derived this code from) on how to setup a UDP chat program which was wonderful for a basic example.
However just as soon as I do non local testing (I switch the IP for the server the client is supposed to connect to from localhost to my real IP), the packet ends up not being received. I can't help but feel that I've setup the server portion of this code wrong.
So here's what I have so far.
Network.h //the UDP networking code.
#pragma once
#include "include/SDL2/SDL_net.h"
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
/*******************************************************************************************
Some things to note about the UDPConnection class.
Init this on both the client and/or server's excutable. No extra work required. Unless your
planning on tracking the activity and data between multiple clients (eg: for multiplayer).
At which point you just memorize and communicate between different ip's manually.
HINT: look at packet->ip;
*******************************************************************************************/
class UDPConnection
{
bool quit;
UDPsocket ourSocket;
IPaddress serverIP;
public:
UDPpacket *packet;
UDPConnection()
{
quit = false;
}
~UDPConnection()
{
SDLNet_FreePacket(packet);
SDLNet_Quit();
}
bool Init(const std::string &ip, int32_t remotePort, int32_t localPort)
{
std::cout << "Connecting to \n\tIP : " << ip << "\n\tPort : " << remotePort << std::endl;
std::cout << "Local port : " << localPort << "\n\n";
// Initialize SDL_net
if (!InitSDL_Net())
return false;
if (!OpenPort(localPort))
return false;
if (!SetIPAndPort(ip, remotePort))
return false;
if (!CreatePacket(65536))
return false;
/* bind server address to channel 0 */
if (SDLNet_UDP_Bind(ourSocket, 0, &serverIP) == -1)
{
printf("SDLNet_UDP_Bind: %s\n", SDLNet_GetError());
return false;
}
return true;
}
bool InitServer(int32_t remotePort, int32_t localPort) {
std::cout << "connecting to port" << remotePort << std::endl;
std::cout << "Local port : " << localPort << "\n\n";
// Initialize SDL_net
if (!InitSDL_Net())
return false;
if (!OpenPort(localPort))
return false;
if (!SetPort(remotePort))
return false;
if (!CreatePacket(65536))
return false;
SDLNet_UDP_Unbind(ourSocket, 0);
return true;
}
bool InitSDL_Net()
{
std::cout << "Initializing SDL_net...\n";
if (SDLNet_Init() == -1)
{
std::cout << "\tSDLNet_Init failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool CreatePacket(int32_t packetSize)
{
std::cout << "Creating packet with size " << packetSize << "...\n";
// Allocate memory for the packet
packet = SDLNet_AllocPacket(packetSize);
if (packet == nullptr)
{
std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
return false;
}
// Set the destination host and port
// We got these from calling SetIPAndPort()
packet->address.host = serverIP.host;
packet->address.port = serverIP.port;
std::cout << "\tSuccess!\n\n";
return true;
}
bool OpenPort(int32_t port)
{
std::cout << "Opening port " << port << "...\n";
// Sets our sovket with our local port
ourSocket = SDLNet_UDP_Open(port);
if (ourSocket == nullptr)
{
std::cout << "\tSDLNet_UDP_Open failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool SetIPAndPort(const std::string &ip, uint16_t port)
{
std::cout << "Setting IP ( " << ip << " ) " << "and port ( " << port << " )\n";
// Set IP and port number with correct endianess
if (SDLNet_ResolveHost(&serverIP, ip.c_str(), port) == -1)
{
std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool SetPort(uint16_t port)
{
std::cout << "Setting up port ( " << port << " )\n";
// Set IP and port number with correct endianess
//IS THE ISSUE HERE?
if (SDLNet_ResolveHost(&serverIP, NULL, port) == -1)
{
std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
// Send data.
bool Send(const std::string &str)
{
// Set the data
// UDPPacket::data is an Uint8, which is similar to char*
// This means we can't set it directly.
//
// std::stringstreams let us add any data to it using << ( like std::cout )
// We can extract any data from a std::stringstream using >> ( like std::cin )
//
//str
memcpy(packet->data, str.c_str(), str.length());
packet->len = str.length();
// Send
// SDLNet_UDP_Send returns number of packets sent. 0 means error
//packet->channel = -1;
if (SDLNet_UDP_Send(ourSocket, -1, packet) == 0)
{
std::cout << "\tSDLNet_UDP_Send failed : " << SDLNet_GetError() << "\n"
<< "==========================================================================================================\n";
//msg.resize(0);
return false;
}
std::cout << "sent to: " << packet->address.host << "\n";
std::cout << "length is: " << packet->len << "\n";
}
inline UDPpacket* recievedData(){
// Check to see if there is a packet wauting for us...
if (SDLNet_UDP_Recv(ourSocket, packet))
{
/*for (int i = packet->len; i < 512; i++) {
//may only be needed for local testing.
packet->data[i] = 0;
}*/
//std::cout << "\tData received : " << packet->data << "\n";
return packet;
}return NULL;
}
inline bool WasQuit()
{
return quit;
}
};
clientSend.cpp //our client's exe.
#include "Network.h"
#include "Graphics.h"
#include <cstdlib>
UDPConnection *udpConnection;
using namespace std;
#define DISPLAY_STRING_ROWS 20
char displayString[DISPLAY_STRING_ROWS][256];
int main(int argc, char **argv){
setup(120, 120, 600, 400); //Inits SDL.
std::string IP = "72.49.67.66";
int32_t remotePort = 333;
int32_t localPort = 222;
udpConnection = new UDPConnection();
udpConnection->Init(IP, remotePort, localPort);
UDPpacket *packet;
for (int i = 0; i < DISPLAY_STRING_ROWS; i++) {
for (int j = 0; j < 256; j++) {
displayString[i][j] = 0;
}
}
while (!udpConnection->WasQuit()){
clear();
packet = udpConnection->recievedData();
#define PACKET_LEN packet->len
#define PACKET_DATA packet->data
static int currentRow = 0;
if (packet != NULL) {
for (int i = 0; i < PACKET_LEN; i++) {
displayString[currentRow][i] = udpConnection->packet->data[i];
}
displayString[currentRow][PACKET_LEN] = 0;
if (currentRow >= DISPLAY_STRING_ROWS) {
currentRow = 0;
}
else {
currentRow++;
}
}
for (int i = 0; i < currentRow; i++) {
if (displayString[i][0] != 0) {
text(displayString[i], 20, 20, PACKET_LEN * 16, 16, 0, 0, 0);
}
}
render();
std::string send;
getline(cin, send);
udpConnection->Send(send);
}
endGame();
}
void displayText() {
}
server.cpp //the server's exe.
#include "Network.h"
#include "Graphics.h"
#include <cstdlib>
//Right now i'm just assuming that the ip is givin every time it's sent to client/server.
UDPConnection *udpConnection;
using namespace std;
int main(int argc, char* args[]) {
//std::string IP = "0.0.0.0"; //Not necessary.
int32_t remotePort = 222;
int32_t localPort = 333;
udpConnection = new UDPConnection();
udpConnection->InitServer(remotePort, localPort);
UDPpacket *packet;
setup(120, 120, 600, 400); //Inits SDL.
char c[10][80000];
int cCount = 0;
int cLength[10];
bool running = true; //Is our game loop running?
while (running) { //--GAME LOOP!--//
clear(); //Clears garbage form SDL.
packet = udpConnection->recievedData();
#define PACKET_LEN packet->len
//#define PACKET_DATA packet->data
if (packet != NULL) {
cout << "we got a message" << endl;
packet->data[PACKET_LEN] = 0;
for (int i = 0; i <= PACKET_LEN; i++) {
c[cCount][i] = packet->data[i];
}
//*c[cCount] = udpConnection->packet->data;
cLength[cCount] = PACKET_LEN;
if (cCount == 9) {
cCount = 0;
}else{
cCount++;
}
}
for (int i = 0; i < cCount; i++) {
text(c[i], 20, i*16, cLength[i] * 16, 16, 0, 0, 0);
}
render(); //Causes SDL to draw what we made to our window.
}
endGame(); //Necessary to properly shutdown SDL.
}
I'd hope I won't have to include the graphic.c and graphics.h files however if this is necessary just ask and I'll post the whole project up on a repo for anyone to reference. I'm hoping however the answer is something really easy that I just kept glancing over.
Here's the link to the tutorial I got the code from. http://headerphile.com/sdl2/sdl2-part-12-multiplayer/
The goal is to have a udp server that's able to receive packets from anyone. The problem is that it simply won't receive over the internet even with the router's ports open.
(Posted on behalf of the OP)
This is pretty much resolved. the problem wasn't the code it was the modem my isp gave me. Turns it's possible and recommended to buy your own modem (facepalm).