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: #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: #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" ); }
|
|
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. |
|
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". |
|
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). |
|
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:
#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 ) { 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 ); GlobalFree(( HGLOBAL ) data ); 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 ) { cout << "Blad listenera\n"; } else cout << "Listener powiazany z portem " << port << "\n"; sf::TcpSocket socket; if( listener.accept( socket ) != sf::Socket::Done ) { cout << "Socket error\n"; } while( 1 ) { if( odbieraniePliku( socket ) != 0 ) break; } getch(); return 0; }
Klient: #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--; 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 ) { 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 ) ); cout << "Wielkosc wysylaniego pliku: " << wielkoscPliku << " bajtow\n"; socket.send( nazwaPliku, 1000 ); if( wielkoscPliku < 1000 ) { socket.send( data, wielkoscPliku ); } 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; }
|
|
« 1 » |