Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[SFML SOCKETY] łączenie przez internet (WAN)

Ostatnio zmodyfikowano 2013-12-29 17:15
Autor Wiadomość
Pokropow
Temat założony przez niniejszego użytkownika
[SFML SOCKETY] łączenie przez internet (WAN)
» 2013-12-28 13:06:30
Witam. Mam napisaną prostą aplikację klient-serwer, która ma za zadanie przesyłać i odbierać stringi. W sieci LAN wszystko działa,ale czy jest możliwość przesyłu tego typu danych przez internet? W routerze mam ustawione przekierowanie portu (Port forwarding) na moje ip. Na komputerze z poza sieci otwieram klienta, wpisuje moje ip i port. Niestety klient wchodzi w pętlę nieskończoną jakieś pomysły? Program pisze w SFML/Network w c++ pod kompilatorem MinGw

Kod klienta:
C/C++
#include <iostream>
#include <SFML/Network.hpp>
#include <windows.h>
#include <process.h>
using namespace std;
#define PORT_DEFAULT 53002
void getPortFromIp( char * ip, int * port, int length = 30 )
{
    bool portFound = 0;
    for( int i = 0; i < length; i++ )
    {
        if( ip[ i ] == ':' )
        {
            ip[ i ] = 0;
            * port = atoi( ip + i + 1 );
            portFound = TRUE;
        }
    }
    if( !portFound )
    {
        * port = PORT_DEFAULT;
    }
   
}

sf::TcpSocket * LPsocket;
bool czyKoniec = FALSE;
void receive( void * )
{
    char buffer[ 500 ];
    size_t rec;
    while( !czyKoniec )
    {
        LPsocket->receive( buffer, 500, rec );
        if( !strcmp( "CLOSE",( const char * ) buffer ) )
        {
            czyKoniec = TRUE;
        }
        cout << "Serwer: " << buffer << endl;
    }
    _endthread();
}

int main()
{
    char buffer[ 500 ];
    size_t rec;
    sf::TcpSocket socket;
    char * ip = new char[ 30 ];
    int port;
    cout << "Podaj adres ip: ";
    cin >> ip;
    getPortFromIp( ip, & port );
    socket.connect( ip, port );
    LPsocket = & socket;
    _beginthread( receive, 0, 0 );
    while( !czyKoniec )
    {
        cin >> buffer;
        if( !strcmp( "CLOSE",( const char * ) buffer ) )
        {
            czyKoniec = TRUE;
        }
        socket.send( buffer, 500 );
       
    }
    system( "pause" );
    return 0;
}

Kod Serwera:

C/C++
#include <iostream>
#include <windows.h>
#include <process.h>
#include <SFML/Network.hpp>
#define PORT_DEFAULT 53002
using namespace std;
bool czyKoniec = FALSE;

sf::TcpSocket * LPsocket;

void send( void * )
{
    while( !czyKoniec )
    {
        char buffer[ 500 ];
        cin >> buffer;
        if( !strcmp( buffer, "CLOSE" ) )
        {
            czyKoniec = TRUE;
        }
        LPsocket->send( buffer, 500 );
    }
    _endthread();
}

int main()
{
    int port;
    cout << "Podaj port: ";
    cin >> port;
    sf::TcpListener listener;
    listener.listen( port );
    sf::TcpSocket socket;
    listener.accept( socket );
    char buffer[ 500 ];
    size_t received;
    LPsocket = & socket;
    _beginthread( send, 0, 0 );
    while( !czyKoniec )
    {
        socket.receive( buffer, 500, received );
        if( !strcmp( "CLOSE", buffer ) )
        {
            czyKoniec = TRUE;
        }
        else
             cout << "Client: " << buffer << endl;
       
    }
   
    system( "pause" );
}


P-100400
domin568
» 2013-12-28 23:54:28
Nie powinieneś zrobić port forwardingu na socket ? A nie na IP ?? W aplikacjach wykorzystuj sf::Packet jest o wiele bardziej bezpieczne.
P-100451
Admixior
» 2013-12-29 03:44:09
1. Nie masz żadnych sprawdzeń czy klient się połączył faktycznie z serwerem. Zaglądnij do dokumentacji na wszystkie funkcje (od connect po send i receive) i obsługuj błędy połączenia, zerwane połączenie i tym podobne. Zapewne dlatego że nie łączy się klient z serwerem, a ty nie sprawdzasz czy nie ma błędów, klient wpada w nieskończoną pętlę.

2. Zakładajam że przekierowanie portu jest ustawione na adres ip komputera z serwerem, odpowiedni port, i protokół TCP/IP (czyli innymi słowy wszystko dobrze). Sprawdź stan zapory dla tej aplikacji. Gdyż domyślnie (jak nie zmieniałeś "zaznaczeń" podczas pierwszego uruchomienia gdy pojawił się komunikat od zapory). To zapora dopuści połączenia tylko z wewnętrznej sieci, a z zewnętrznej (internetu) odrzuci.

Za nie składność języka sorry (piszę późno w nocy ten post).


Co do tego co zrobiłeś to: musisz uważać na TCP/IP gdyż to strumień i albo (jak napisał kolega wyżej) korzystać z gotowych paczek, albo samemu zaimplementować pseudo-paczkę wysyłając rozmiar, gdyż TCP/IP to strumieniowa transmisja, czyli możesz nie odróżnić końca poprzedniej paczki od początku następnej. W przypadku niewielkiej ilości danych nie ma problemu, ale jak zaczniesz wysyłać setki kilobajtów to może się okazać że twój program się pogubi. Nikt nie daje gwarancji że to co wyślesz dojdzie OD RAZU w całości. Zawsze dojdzie i będzie odpowiednia koleność, ale może się okazać że najpierw dojdzie "CLO" a później "SE", a nie od razu "CLOSE".
P-100455
Pokropow
Temat założony przez niniejszego użytkownika
» 2013-12-29 14:43:53
To prawda że nie ma obsługi błędów(nie chciało mi się jej na razie robić ),więc zrobię ją zaraz. Co do przesyłu to zawsze przesyłam stałą wartość i są to małe paczki danych,ale klient nawet nie zaczyna obierania pliku bo wchodzi w pętlę nieskończoną i ciągle wyświetla "serwer: ", zaraz załatwię obsługę błędów i napiszę co się stało.

Jeżeli chodzi o port forwarding to podejrzewam że w tym jest wszystko dobrze (to nie pierwszy serwer na który forwarduję port, a zawsze działało) - > w opcjach routera w zakładce "forwarding" wpisuje dany port protokół TCP i moje lokalne ip.

Czy na pewno można tak łączyć się przez internet (nie trzeba może użyć jakiś dodatkowych metod lub funkcji?), bo jak łączę się ze zdalnym komputerem podpiętym pod tą samą sieć (wpisując lokalne ip) to wszystko działa. Ktoś może pisał podobne aplikacje do przesyłu danych przez internet?

Nie korzystam z pakietów bo łatwiej mi przesyłać dane normalnie, a jak przesyłam większe pliki to najpierw wysyłam wielkość i nazwę pliku , a potem korzystam z pętli w której wysyłam mniejsze części pliku aż cały się wyśle.

Aha a zaporę chyba odblokowałem (niestety teraz tego nie sprawdzę bo nie mam dostępu do telefonu z internetem ,a klient musi mieć inne zewnętrzne ip, bo inaczej muszę przesyłać przez lan).
P-100493
Pokropow
Temat założony przez niniejszego użytkownika
Do zamknięcia
» 2013-12-29 17:15:30
Dodałem obsługę błędów i działa dobrze (wcześniej może faktycznie zapomniałem o firewallu)

Dla zainteresowanych źródła:
Serwer:
C/C++
/**
Serwer
TCP/IP Connection
*/

#include <iostream>
#include <SFML/Network.hpp>
#include <SFML/System.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <fstream>
#include <string.h>
#include <windows.h>
using namespace std;

int odbieraniePliku( sf::TcpSocket & socket )
{
    /*cout << "Receiving file\n";*/
    size_t wielkoscPliku;
    char nazwaPliku[ 1000 ];
    std::size_t recieved;
    if( socket.receive( & wielkoscPliku, sizeof( wielkoscPliku ), recieved ) != sf::Socket::Done )
    {
        cout << "!!! Recieve error -> err 1 !!!!\n";
        cout << "! Koniec poloczenia !\n";
        return 1;
    }
    size_t ile = wielkoscPliku;
   
    char * data =( char * ) GlobalAlloc( GMEM_FIXED, wielkoscPliku + 2000 );
    cout << "Wielkosc pliku: " << ile << " bajtow\n";
   
    if( socket.receive( nazwaPliku, 1000, recieved ) != sf::Socket::Done )
    {
        cout << "!!! Recieve error -> err 2 !!!\n";
        cout << "Koniec poloczenia\n";
        return 2;
    }
    cout << "Nazwa pliku: " << nazwaPliku << endl;
    size_t otrzymane = 0;
    if( ile < 1000 )
    {
        if( socket.receive( data, ile, recieved ) != sf::Socket::Done )
        {
            cout << "!!! Recieve error -> err 3 !!!\n";
            cout << "Koniec poloczenia\n";
            return 3;
        }
        otrzymane = recieved;
    }
    else
    {
        long long int i = 0;
        while( i < ile )
        {
            socket.receive( data + i, 100, recieved );
            i += 100;
        }
       
    }
    string temp;
    temp = nazwaPliku;
    ofstream plik( temp.c_str(), ios_base::binary | ios_base::out );
    plik.write( data, ile );
    //plik.write(data,wielkoscPliku);
    //delete[] data;
    GlobalFree(( HGLOBAL ) data );
    //delete[] newDATA;
    plik.close();
    cout << "Odebrano Plik: " << nazwaPliku << "\n\n"
   
    "################################################################################\n\n";
    return 0;
}

int main()
{
    std::size_t recieved;
    int port;
    cout << "Podaj port: ";
    cin >> port;
   
   
    sf::TcpListener listener;
    if( listener.listen( port ) != sf::Socket::Done )
    { /** OBSLUGA BLEDOW */
        cout << "Blad listenera\n";
    }
    else
         cout << "Listener powiazany z portem " << port << "\n";
   
    sf::TcpSocket socket;
    if( listener.accept( socket ) != sf::Socket::Done )
    { /** OBSLUGA BLEDOW */
        cout << "Socket error\n";
    }
    while( 1 )
    {
        if( odbieraniePliku( socket ) != 0 )
             break;
       
    }
    getch();
   
   
   
   
    return 0;
}
Klient:
C/C++
#include <iostream>
#include <SFML/Network.hpp>
#include <SFML/System.hpp>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <conio.h>
#include <windows.h>
using namespace std;

void doNazwyPliku( const char sciezka[], char cel[], int dlugosc = 300 )
{
    dlugosc--; /** numer ostatniego elementu tablicy */
    while( 1 )
    {
        if( sciezka[ dlugosc ] == '\\' )
        {
            dlugosc++;
            strcpy( cel, sciezka + dlugosc );
            break;
        }
        else if( dlugosc == 0 )
        {
            strcpy( cel, sciezka );
            break;
        }
        dlugosc--;
       
    }
}

int wyslijPlik( sf::TcpSocket & socket )
{
    /*socket.send("Receive File",20);*/
    char * nazwaPliku = new char[ 1000 ];
    cout << "Podaj nazwe pliku: ";
    cin >> nazwaPliku;
   
    char * temp = new char[ 1000 ];
    temp = nazwaPliku;
    doNazwyPliku( temp, nazwaPliku );
   
   
    size_t wielkoscPliku;
   
    fstream plik( temp, ios_base::in | ios_base::binary );
    if( !plik.good() )
    {
        cout << "Error: Cannot open file \"" << nazwaPliku << " \"!";
        return 0;
    }
    plik.seekg( 0, ios::end );
    wielkoscPliku = plik.tellg();
    plik.seekg( 0, ios::beg );
    char * data =( char * ) GlobalAlloc( GMEM_FIXED, wielkoscPliku + 2000 );
   
   
    cout << nazwaPliku << endl;
    plik.read( data, wielkoscPliku );
    int ile = wielkoscPliku;
    socket.send( & wielkoscPliku, sizeof( wielkoscPliku ) ); /** Wysylanie wielkosci pliku */
    cout << "Wielkosc wysylaniego pliku: " << wielkoscPliku << " bajtow\n";
   
    socket.send( nazwaPliku, 1000 ); /** Wysylanie nazwy pliku */
    if( wielkoscPliku < 1000 )
    {
        socket.send( data, wielkoscPliku ); /** Wysylanie danych */
    }
    else
    {
        long long int i = 0;
        while( i < wielkoscPliku )
        {
            socket.send( data + i, 100 );
            i += 100;
        }
    }
    GlobalFree(( HGLOBAL ) data );
    delete[] nazwaPliku;
    delete[] temp;
    plik.close();
    Sleep( 20 );
    return 1;
}



int main()
{
   
    char IP[ 25 ];
    cout << "Podaj IP: ";
    cin >> IP;
    int port;
    cout << "Podaj port: ";
    cin >> port;
    sf::TcpSocket socket;
    sf::Socket::Status status = socket.connect( IP, port );
    if( status != sf::Socket::Done )
    {
        cout << "Error! Polaczenie nie udalo sie!\n";
    }
    while( 1 )
    {
        if( !wyslijPlik( socket ) )
             cout << "Nie udalo sie wyslac pliku";
       
    }
   
    getch();
   
    return 0;
}
P-100543
« 1 »
  Strona 1 z 1