2

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
user3440251
  • 33
  • 2
  • 8
  • Step 1: Get a network sniffer. I like wireshark myself: https://www.wireshark.org/ ie: you don't know where the packets are coming from and going to and where they are dropping without watching them. (and possibly checking a list of open ports too) – ebyrob Mar 17 '17 at 18:50
  • I've never thought of using wireshark this way nor using it on windows... genius thanks. – user3440251 Mar 17 '17 at 18:52
  • After reading what I can of some of this without knowing anything about your SDL network library. **The packet ends up not being received.** UDP is *always* received by non-fire walled machines whether they're even listening. I'd first make 100% sure with a sniffer on the server that packets are indeed arriving. This will tell you if you have a problem where the client isn't sending or a firewall is blocking (software or hardware) or the server is receiving data and just not reacting to it in the debugger (not listening). – ebyrob Mar 17 '17 at 19:14
  • If i can find it there was a ftp server type of udp implementation for sdl_net. it was hard for me to breakdown and figure out where i went wrong though. finding a simple udp example has been rather impossible at the moment so if i figure it out i'm definitely sharing. – user3440251 Mar 17 '17 at 22:50
  • yeah i think setting up a repo will be necessary at this point. – user3440251 Mar 17 '17 at 22:50
  • I don't know about this "sdl_net" you're using, but your code doesn't look so horrible. Personally if I was going to bother with UDP I'd be using a sockets API directly. here's one tutorial on unix: https://www.cs.rutgers.edu/~pxk/417/notes/sockets/udp.html and another using winsock: http://www.binarytides.com/udp-socket-programming-in-winsock/ If you get into trouble with using sockets directly, there are thousands more programmers who can likely help you. Otherwise: netstat, wireshark (or tcpdump). And if I *did* need a network library, I'd be going for substance say: ZeroMQ etc – ebyrob Mar 18 '17 at 18:21
  • i've been finding a lot of posts just like this which makes me think sdl_net is somehow broken... it's so strange. i've tested that old code that i thought worked and i discovered that i was mistaken... anyway the reason for sdl_net was because it's supposed to be compatible with all platforms that sdl ports to and from what i heard apparently sdl ports to consoles now... which makes me want to stick to this for multiplayer and server testing. however if i truly can't get this to work then i hope that a more basic UDP socket api would be able to cover everything i'm wanting. – user3440251 Mar 18 '17 at 23:58
  • my bad here it is. http://stackoverflow.com/questions/35527272/sdlnet-networking-not-working – user3440251 Mar 18 '17 at 23:58
  • alright the issue was on my end not with sdl_net. my modem doesn't like setting a udp server... though it will receive udp packets if i'm specifically listening for another ip which makes no sense to me... so the protforwarding doesn't work for the udp end sadly. anyway thanks to all of you for taking a look and trying to help out. appreciate it. – user3440251 Mar 20 '17 at 01:15

1 Answers1

1

(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).

halfer
  • 19,824
  • 17
  • 99
  • 186