I Socket non funzionano con ip pubblico

di il
11 risposte

I Socket non funzionano con ip pubblico

Salve!
Stavo giocando (termine usato prima dell'edit, "smanettare", che sulla Treccani risulta "Utilizzare il computer con grande abilità e disinvoltura, sperimentando o modificando funzioni e programmi. "...)come mi capita nei momenti liberi con le SFML e i suoi socket(TCP/IP), ho creato un server che gestisce svariati client (usando 2 thread per ognuno, 1 input e 1 output) e un client con 2 thread aggiuntivi per i/o, prima o poi passo a thread & i/o asincrono, ma per ora sto pensando a divertirmi e quindi uso solo le cose che conosco.
Quello che le mie applicazioni fanno o dovrebbero fare è connettersi al server e dare gli input e le coordinate del mouse, poi il server li comunica a tutti i client e i client visualizzano un immagine su schermo che si muove seguendo le coordinate ricevute, quindi un immagine che segue il cursore del client (e visibile da tutti i client).
Ora, in locale funziona, e anche con hamachi: la scincronizzazione non è delle migliori (se posso considerarla sincronizzazione), all'inizio e in parti casuali dell'esecuzione l'input và lentamente e ci mette qualche secondo a ristabilizzarsi, ma riesco a vedere l'immagine che segue chiaramente il cursore.
Invece, con un account no-ip e un dns pubblico si connette normalmente ma i dati iniziano a essere corrotti, con piccole parti corrette (circa il 2% di tutto) e altre parti che sono caratteri casuali.
Esempio:
Quello che dovrebbe essere (e che risulta usando hamachi o ip locale)

Come risulta connesso al dns


Perchè?

I thread di I/O

ClieSide
void inputThread()
{
    Socket::Status status;
    char buffer[MAX_BUFFER];
    size_t received;
    bool connected = true;
    client.socket.setBlocking(true);

    while(connected == true)
    {
        status = client.socket.receive(buffer, MAX_BUFFER, received);
        if(status != Socket::Done && status != Socket::NotReady)
        {
            cout <<"Disconnected." <<endl;
            connected = false;
        }
        else if (status == Socket::Done && buffer[0] != '\0')
        {
            cout <<"Received " <<buffer<<endl;
            inputString = buffer;
            ISReadable = true; //La variabile booleana che controlla se l'input è leggibile dal main. Una volta letta viene riportata a false, nel main.
        }
    }
}


void outputThread()
{
    stringstream ss;
    string outputString;
    char buffer[MAX_BUFFER];
    Vector2i localPosition;
    client.socket.setBlocking(true);

    while(true)
    {

        localPosition = Mouse::getPosition(window);
        outputString.clear();
        ss.str(string());
        ss << localPosition.x;
        ss << "|";
        ss << localPosition.y;
        ss << "|";
        if(Mouse::isButtonPressed(Mouse::Left))  //Serie di input non ancora utilizzata dal server. 
            ss << "t";
        else
            ss << "f";
        ss << "|";
        if(Mouse::isButtonPressed(Mouse::Right))
            ss << "t";
        else
            ss << "f";


        outputString = ss.str();
        strcpy(buffer, outputString.c_str());
        //cout <<buffer<<endl;
        outputString = ss.str();
        strcpy(buffer, outputString.c_str());
        client.socket.send(buffer, MAX_BUFFER);
        sleep(milliseconds(2));
    }
}
Il server manda sempre i dati corretti. Buffer è corretto, lo stampo su schermo ogni volta prima di inviarlo
        if(changeOString) //changeOString true = read OS1, changeOString false = read OS2
        {
            strcpy(buffer, outputString1.c_str());
            cout <<buffer<<endl;
        }
        else
        {
            strcpy(buffer, outputString2.c_str());
            cout <<buffer<<endl;
        }
        status = client[id].socket.send(buffer, MAX_BUFFER);
        sleep(milliseconds(2));
[/code]

Cosa può essere?
P.s.
Perdonate quello che leggerete, l'ho fatto in una notte giusto perchè non avevo sonno e volevo programmare, non ho rispettato nessuno stile.
Esempio, tutti gli attributi delle mie classi sono pubblici, prometto che appena risolvo i problemi principali creo un codice come si deve ahaha
Non carico tutto il codice di entrambe le applicazioni perchè sarebbero 600 righe di pugni agli occhi. Se serve per forza, proverò a fare del mio meglio per migliorare l'aspetto

11 Risposte

  • Re: I Socket non funzionano con ip pubblico

    Devi STUDIARE come funziona il protocollo TCP/IP, NEI DETTAGLI.
    Gli errori che rilevi sono legati ad un errore concettuale che si fa quando si lavora con questo protocollo, che consiste nella seguente idea (SBAGLIATA): SE INVII un messaggio di 10 byte, RICEVERAI un messaggio di 10 byte.

    SBAGLIATO

    MA NON SOLO

    l'infrastruttura di rete puo' spezzare il messaggio in quante parti vuole, ed inviarlo a pezzettini, al limite di 1 byte alla volta. OPPURE concatenare piu' messaggi ed inviarteli, OPPURE concatenarne alcuni e l'ultimo spezzarlo (OVVIAMENTE NON SPEZZA i messaggi interni)

    QUINDI, quando ricevi un buffer dal socket, DEVI SAPERE A PRIORI come ricomporre il messaggio originale.

    Il TCP/IP e' un protocollo masato su STREAM, cioe' su un flusso continuo di byte. QUesto paradigma va bene per il trasferimento di file, per il video e l'audio, ma NON per l'invio di MESSAGGI.

    Quello che ti consiglio (ESISTONO gia' librerie in tal senso, ma implementarne una auta a capire il problema) e' quello di implementare una libreria che implementa il paradigne della comunicazione mediante MESSAGGI, dove un MESSAGGIO e' una sequenza di byte in cui i primi due byte sono la lunghezza del messaggio.

    In questo modo, quando ricevi IL PRIMO pacchetto TCPIP, saprai che i primi 2 byte sono la lunghezza del messaggio, quindi dovrai accumulare abbastanza pachetti da completare il messaggio, e SALVARE gli eventuali byte rimanenti perche' faranno parte del messaggio successivo.

    ATTENTO, che questo implica che il tuo messaggio non puo' essere piu' lungo di 65535 byte (2^16-1). Se devi inviare messaggi piu' lunghi, puoi inventarti un meccanismo alternatici, che ne so, ad esempio:

    - i messaggi possono essere al massimo lunghi 32767 byte
    - se i primi 2 byte hanno un valore maggiore di 32767, allora l'header e' di 4 byte, con messaggio che possono essere fino lunghi fino a 4GB (2^32-32768)

    Nota: cambia il titolo del thread perche' qui il DNS non centra proprio nulla
  • Re: I Socket non funzionano con ip pubblico

    migliorabile ha scritto:


    Devi STUDIARE come funziona il protocollo TCP/IP, NEI DETTAGLI.
    Gli errori che rilevi sono legati ad un errore concettuale che si fa quando si lavora con questo protocollo, che consiste nella seguente idea (SBAGLIATA): SE INVII un messaggio di 10 byte, RICEVERAI un messaggio di 10 byte.

    SBAGLIATO

    MA NON SOLO

    l'infrastruttura di rete puo' spezzare il messaggio in quante parti vuole, ed inviarlo a pezzettini, al limite di 1 byte alla volta. OPPURE concatenare piu' messaggi ed inviarteli, OPPURE concatenarne alcuni e l'ultimo spezzarlo (OVVIAMENTE NON SPEZZA i messaggi interni)

    QUINDI, quando ricevi un buffer dal socket, DEVI SAPERE A PRIORI come ricomporre il messaggio originale.

    Il TCP/IP e' un protocollo masato su STREAM, cioe' su un flusso continuo di byte. QUesto paradigma va bene per il trasferimento di file, per il video e l'audio, ma NON per l'invio di MESSAGGI.

    Quello che ti consiglio (ESISTONO gia' librerie in tal senso, ma implementarne una auta a capire il problema) e' quello di implementare una libreria che implementa il paradigne della comunicazione mediante MESSAGGI, dove un MESSAGGIO e' una sequenza di byte in cui i primi due byte sono la lunghezza del messaggio.

    In questo modo, quando ricevi IL PRIMO pacchetto TCPIP, saprai che i primi 2 byte sono la lunghezza del messaggio, quindi dovrai accumulare abbastanza pachetti da completare il messaggio, e SALVARE gli eventuali byte rimanenti perche' faranno parte del messaggio successivo.

    ATTENTO, che questo implica che il tuo messaggio non puo' essere piu' lungo di 65535 byte (2^16-1). Se devi inviare messaggi piu' lunghi, puoi inventarti un meccanismo alternatici, che ne so, ad esempio:

    - i messaggi possono essere al massimo lunghi 32767 byte
    - se i primi 2 byte hanno un valore maggiore di 32767, allora l'header e' di 4 byte, con messaggio che possono essere fino lunghi fino a 4GB (2^32-32768)

    Nota: cambia il titolo del thread perche' qui il DNS non centra proprio nulla

    Sò che il tcp/ip (a differenza dell'udp/ip) spezza i pacchetti, infatti stavo pensando di implementare qualcosa tipo "start" e "end" in ogni buffer mandato. Il metodo dei byte iniziali sembra ovviamente più efficiente
    Non sapevo invece che il tcp/ip non è buono per i messaggi.
    Non ho capito però se dovrei cambiare protocollo o libreria... O implementare da solo i byte all'inizio del buffer e risolvere lo stesso il problema.
    Tornerò qui quando mi sarò informato meglio sul problema, sempre se non riesco a risolverlo prima.
    Ma... come è possibile che questo errore avvenga soltanto con l'ip pubblico?
    Non so come rinominare il thread ho messo il titolo che mi sembrava più opportuno al problema iniziale ma.. non mi sembra sia cambiato molto
  • Re: I Socket non funzionano con ip pubblico

    Penso che, a priori, serva la comprensione di cosa sia TCP, e cosa IP.
    Non sono affatto sinonimi, nè la stessa cosa, nè lo è UDP.
    Per dare la "diagnosi" servirebbe vedere bene cos'è socket (nel tuo programma)
  • Re: I Socket non funzionano con ip pubblico

    Il socket è gestito dalle SFML, quello che io posso fare è "connect" "send" e "receive".
    Tcp/ip è il nome utilizzato per i due protocolli che usano le SFML, il Transmission control protocol e l'Internet protocol.
    Ho studiato anche questo... non l'ho appreso da internet, ma da un libro di scuola dove ci sono tutte le cose essenziali di questi protocolli.
    (In sistemi e reti la parte teorica, quindi non programmazione, ora sto facendo l'udp in tps con il C, e presto inizierò anche il tcp.
    Ma, parere non personale, imparerò ad usare i due protocolli in un modo molto più inefficiente di quello che già faccio.)
  • Re: I Socket non funzionano con ip pubblico

    P.s.
    Ho già fatto anche i socket udp con il C su linux (a scuola) e il tcp in c su windows (individualmente), non li uso perchè trovo più comode le sfml.
  • Re: I Socket non funzionano con ip pubblico

    Devid1910 ha scritto:


    Il socket è gestito dalle SFML, quello che io posso fare è "connect" "send" e "receive".
    Tcp/ip è il nome utilizzato per i due protocolli che usano le SFML, il Transmission control protocol e l'Internet protocol.
    https://www.sfml-dev.org/faq.php#network-tcp-vs-ud
  • Re: I Socket non funzionano con ip pubblico

    Interessante, non avevo mai notato quella pagina sul sito anche se è a 200 pixel dalla categoria "learn"
    Ma c'è scritto (o meglio ricopiato) tutto quello che c'è nei tutorial, quindi niente di nuovo...
  • Re: I Socket non funzionano con ip pubblico

    Devid1910 ha scritto:


    Interessante, non avevo mai notato quella pagina sul sito anche se è a 200 pixel dalla categoria "learn"
    Ma c'è scritto (o meglio ricopiato) tutto quello che c'è nei tutorial, quindi niente di nuovo...
    il "nuovo" è: ma che tipologia di socket utilizzi? TCP o UDP?
  • Re: I Socket non funzionano con ip pubblico

    Devid1910 ha scritto:


    Salve!
    Stavo giocando [...] come mi capita nei momenti liberi con le SFML e i suoi socket(TCP/IP)
  • Re: I Socket non funzionano con ip pubblico

    Devid1910 ha scritto:


    Devid1910 ha scritto:


    Salve!
    Stavo giocando [...] come mi capita nei momenti liberi con le SFML e i suoi socket(TCP/IP)
    per favore mi scrivi dove definisci la mitica socket?
  • Re: I Socket non funzionano con ip pubblico

    Nel file "Client.hpp", attributo pubblico di tipo "TcpSocket".
    Il socket rimane blocking in tutte le parti del programma.
Devi accedere o registrarti per scrivere nel forum
11 risposte