ERLEDIGT
JA
JA
ANTWORTEN
4
4
ZUGRIFFE
758
758
EMPFEHLEN
-
23.03.11 08:27 #1
- Registriert seit
- Mar 2011
- Beiträge
- 15
Schönen Guten Tag,
Ich hab die letzten Tage meine ersten Schritte in der Socketprogrammierung gemacht und dachte um das Wissen zu vertiefen wage ich mich an einen einfachen FTP - Clienten.
Ich bin dabei auf Probleme gestoßen, die evtl mehr Grundwissen über die Behandlung von Sockets im Betriebssystem oder das Management von Sockets für FTP - Clienten erfordern.
Folgendes Problem:
Ich bin in der Lage eine Verbindung zum Control - Port des FTP Servers herzustellen und kann mit diesem vorerst problemlos kommunizieren.
Auch ist es mir möglich eine Passiv - Verbindung zum Server herzustellen über Serverbefehl
"PASV\r\n" wird mir vom Server der Data - Port zur Verfügung gestellt, über welchem ich mich vorerst ohne Probleme verbinden kann.
Auch einfache Befehle wie "NLST\r\n" kann ich senden und die Antwort über den mit Data-Port verbundenen Socket empfangen.
Folgendes ist mir dabei aufgefallen: Jeder dieser Befehle erfordert stets ein erneuten Aufruf von "PASV\r\n", damit mir vorübergehend ein Port geöffnet wird.
Das heißt aber auch, dass jedesmal ein neuer Socket vom Betriebssystem zur Verfügung gestellt werden muss, dessen Ausgangsport nun nicht mehr um nur 1 höher ist als der Ausgangsport meines Sockets mit dem ich den Control - Port (21) anspreche.
Auszug Netstat:
http://www.bilderload.com/bild/96792/netstatSRBP0.jpg
Meines Wissens nach muss der Data-Port genau um eins höher sein als der Control - Port des Clients.
Frage:
Gibt es Wege den Ausgangsport manuell zu bestimmen, ohne automatische Zuweisung des Betriebssystems?
Oder gibt es Wege einen Socket der zuvor connected war zu disconnecten und mit einem neuen Zielport zu verbinden, ohne, das er mit closesocket() freigegeben wird, denn jedesmal, wenn ich mit socket() einen Neuen erstelle ist der gewünschte Ausgangsport nicht mehr nur um 1 höher als der Ausgangsport des Sockets, der mit dem Controlport(21) verbunden ist, wie auch im Netstat erkenntlich.
Realisiert habe ich das folgendermaßen:
Selbstdefinierte Fkt:
Code c:1 2 3 4 5 6
int sendCom(int sock, char* msg, int* status); int connect_data(struct in_addr hostip, unsigned short ftpPort); /* retrieves the created Socked connected to the passive-port of the Server*/ struct in_addr getHostIp(char* hostName); unsigned short passivePort(int ctrlSock); unsigned short buildPort(char*);
main():
Wesentliches ab
/*Kommunikation mit Server ================================================== */
Code c:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
int main() { char key = 0; char buffer[BUF_LEN] = ""; unsigned short ftpPort = 0; int status = 0; int bytes = 0; int sock = 0; int sock_data = 0; struct sockaddr_in addr; /* Control Port Server */ struct sockaddr_in addr_data; /* Passiver Datenport Server */ struct hostent host; /* nötig um Informationen aus gethostbyname zu erhalen*/ struct in_addr hostip; /* nötig um die IP - Adresse des Hosts aus "host.h_addr_list[0]" zu erhalten*/ WSADATA wsa; if (WSAStartup(MAKEWORD(1,1), &wsa) != 0) { printf("Failed to load windows specific DLL's for Sockets"); return 1; } else { printf("%s\n", wsa.szDescription); printf("%s\n", wsa.szSystemStatus); } sock = socket(AF_INET, SOCK_STREAM, 0); /* Erstellen des Control - Port Sockets*/ if (sock == -1) { printf("Failed to create Socket\n"); return 1; } else { printf("Socket created...\n"); } /* Hostaddresse aus durch gethostbyname() ermitteln*/ host.h_length = 0; host = *gethostbyname("ftp.getintern.ge.ohost.de"); if (host.h_length != 0) { printf("Hostename: %s\n", host.h_name); printf("Addresslaenge: %d\n", host.h_length); printf("Addresstyp: %d AF_INET: %d\n", host.h_addrtype, AF_INET); hostip = *(struct in_addr*)host.h_addr_list[0]; printf("Hostip: %ul -- %s\n", hostip.s_addr, inet_ntoa(hostip)); } else { printf("failed gethostbyname()\n"); } addr.sin_family = AF_INET; addr.sin_addr = hostip; addr.sin_port = htons(21); /* Verbindung zu Controlport 21 des Servers herstellen, Ausgangsport vom Betriebssystem automatisch gewählt */ if (connect(sock, (const sockaddr*)&addr, sizeof(addr)) != 0) { printf("Failed to connect...\n"); } else { printf("Kommunikation mit Server startet...\n"); /*Kommunikation mit Server ================================================== */ /* Ne Menge Befehle um die Funktionalität des Controlports zu testen */ sendCom(sock,"", &status); bytes = sendCom(sock, "USER blaaaaaa\r\n", &status); bytes = sendCom(sock, "PASS undblaaa\r\n", &status); bytes = sendCom(sock, "OPTS UTF8 ON\r\n", &status); bytes = sendCom(sock, "HELP\r\n", &status); bytes = sendCom(sock, "SYST\r\n", &status); bytes = sendCom(sock, "PWD\r\n", &status); bytes = sendCom(sock, "MKD WhatDir\r\n", &status); ftpPort = passivePort(sock); /* Senden von "PASV\r\n" und Ermittlung des geöffneten Ports*/ /* Erstellen eines neuen Sockets und verbinden mit neu geöffneten passiven Dataport hier scheint das Problem zu liegen */ sock_data = connect_data(getHostIp("ftp.getintern.ge.ohost.de"), ftpPort); bytes = sendCom(sock, "TYPE A\r\n", &status); bytes = sendCom(sock, "NLST\r\n", &status); bytes = sendCom(sock_data, "", &status); bytes = sendCom(sock, "", &status); bytes = sendCom(sock, "PWD\r\n", &status); /* Bis hierhin keine Probleme, alle Daten über Control und Dataport konnten empfangen werden */ /*erneuter Test der Verbindung mit passive Port auch hier wird wiederrum ein neuer Socket erstellt, dieser hat einen um 2 höheren Ausgangsport als der Control - port - socket, dennoch wird auch diesmal der Befehl "NLST\r\n" problemlos ausgeführt und es können beliebig Befehle über Controlport gesendet werden*/ ftpPort = passivePort(sock); sock_data = connect_data(getHostIp("ftp.getintern.ge.ohost.de"), ftpPort); bytes = sendCom(sock, "TYPE A\r\n", &status); bytes = sendCom(sock, "NLST\r\n", &status); bytes = sendCom(sock_data, "", &status); bytes = sendCom(sock, "", &status); bytes = sendCom(sock, "PWD\r\n", &status); /* Erneute passiv - Verbindung herstellen, diesmal aber um eine textdatei zu erstellen, der Ausgangsport der passiver Verb ist diesmal um 3 höher als der des ControlSockets*/ ftpPort = passivePort(sock); sock_data = connect_data(getHostIp("ftp.getintern.ge.ohost.de"), ftpPort); bytes = sendCom(sock, "TYPE A\r\n", &status); bytes = sendCom(sock, "STOR Test.txt\r\n", &status); bytes = sendCom(sock_data, "BULLSHIT", &status); /*Diese Textdatei konnte problemlos erstellt werden JEDOCH ist es mir nich mehr möglich Befehle über das Socket, welches mit dem Control Port verbunden ist zu versenden All die folgenden Befehle sind erfolglos*/ bytes = sendCom(sock, "PWD\r\n", &status); bytes = sendCom(sock, "MKD WhatDir\r\n", &status); bytes = sendCom(sock, "QUIT\r\n", &status); /*Dieses Problem würde auch auftreten, hätte ich die letzte Übertragung über das Data Socket ganz an den Anfang gesetzt, also es scheint probleme beim Upload zu geben*/ /*Kommunikation mit Server ================================================== */ } closesocket(sock); closesocket(sock_data); printf("Sockets closed...\n"); WSACleanup(); key = getchar(); return 0; }
connect_data():
Code c:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
int connect_data(struct in_addr hostip, unsigned short ftpPort) { static int sock_data = -1; struct sockaddr_in addr_data; /*Hier wird jedesmal ein neues Socket erstellt, sobal ein neuer Passiver Port bekannt ist, jedesmal steigt der Ausgangsport um 1 siehe Netstat*/ if (sock_data != -1) { closesocket(sock_data); } sock_data = socket(AF_INET, SOCK_STREAM, 0); if (sock_data == -1) { printf("Failed to create Datasocket\n"); return 1; } else { printf("Datasocket created...\n"); } addr_data.sin_family = AF_INET; addr_data.sin_addr = hostip; addr_data.sin_port = htons(ftpPort); if (connect(sock_data, (const sockaddr*)&addr_data, sizeof(addr_data)) != 0) { printf("Failed to connect FTP - DATA - PORT\n"); } else { printf("Datentransfer startet...\n"); } return sock_data; }
sendCom():
Code c:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
int sendCom(int sock, char* msg, int* status) { int len = strlen(msg); int bytes = 0; int allBytes = 0; char buffer[BUF_LEN] = ""; /*BUF_LEN should be at least 4*/ fd_set readSock; int selectRes = 1; struct timeval tv; if (msg[0] != 0) { bytes = send(sock, msg, len, 0); if (bytes <= 0) { printf("ERROR: Failed to send Message\n"); return -1; } } while (selectRes) { tv.tv_sec = 3; tv.tv_usec = 0; FD_ZERO(&readSock); FD_SET(sock, &readSock); selectRes = select(sock + 1, &readSock, NULL, NULL, &tv); if (selectRes) { bytes = recv(sock, buffer, sizeof(buffer) - 1, 0); if (bytes == SOCKET_ERROR) { printf("ERROR: Fehler bei der Uebertragung...\n"); bytes = 0; return - 1; } else if (bytes == 0) { printf("ERROR: Connection has been closed\n"); return - 1; } else if (bytes > 0) { buffer[bytes] = 0; printf("%s", buffer); if (bytes < sizeof(buffer) - 1) selectRes = 0; if (allBytes == 0) { buffer[4] = 0; (*status) = strToInt(buffer); } allBytes += bytes; } } else { printf("No Data to read for this Socket!\n"); } } return allBytes; }
Nunja ich hoffe jemand tut sich dieses Leid hier an.
ich bin über jegliche Antworten dankbar.
Gruß
EDIT: Mir ist gerade aufgefallen, das ich erwähnte der Ausgangsport zum DataPort des Servers müsse um 1 größer sein als der Ausgangsport des Clienten zum Controlport des Servers, dabei MUSS er um 1 niedriger sein.
Nichtsdestotroz kommt eine Verbindung zustande und ich kann auch vom Server Daten empfangen und senden.
Das löst aber immernoch nicht das problem, das ich jedesmal, wenn ich einen neuen passiver Port vom Server bekomme ein neues Socket erstellen muss und nach einem Upload keine Kommunikation mit dem Server über den Controlport mehr möglich ist.Geändert von Eburneolus (23.03.11 um 10:40 Uhr)
-
Hallo,
Hab mir deinen Code nicht genau angesehn. Um den Code etwas übersichtlicher zu gestalten, würd ich eine Klasse erstellen und die Funktionen dann im main aufrufen, z.b.:
Code cpp:1 2
ftp.send("NLST");//fügt \r\n and und sendet automatisch, funktioniert auch mit mehr Strings cmd=fpt.recv();//empfängt den retcode und schreibt den Wert in cmd (int)
Letztlich baute ich mir noch eine download Funktion, die einen neue pasv Verbindung aufbaut, die entsprechende Daten runterlädt, in eine Datei speichert und den Datenport wieder schließt. Diese Funktion kann man dann so oft ausführen wie man es halt braucht.
Den Socket schließe ich mit closesocket(d_sock); und d_sock=INVALID_SOCKET;.
Der Filezilla Client macht es laut Socketsniffer genau so. Ich habe mir dazu keine Protokolle über FTP durchgelesen sonder hab die Packets gesnifft, und genau das selbe wie der Filezilla Client gemacht.
Ich hoffe ich konnte dir helfen.
Grüße Poseidon
-
23.03.11 10:27 #3
- Registriert seit
- Mar 2011
- Beiträge
- 15
Hab wohl den [C] - Tag vorm Topic vergessen.
Seis drum zu deinen Vorschlägen:
Die send und recv Funktion hab ich bereits realisiert.
Das Problem ist die Passive Verbindung.
Vor jedem Befehl, der eine Verbindung mit dem Datenport erfordert rufe ich "PASV" auf in Fkt
passivePort(sock), welche mir den Port zurückgibt mit dem ich dann in connect_data() das nötige Socket erstelle und mit dem Server verbinde.
Danach kann ich je nach Befehl Daten empfangen oder senden.
Nun ist es mir jedoch nicht mehr möglich, nachdem ich Daten z.B. die Textdatei geuploaded habe weitere Befehle an den ControlPort zu senden und ich versteh die Ursache nicht, zumal es in FileZilla ohn Probleme läuft.
PS: Wie kann man den C - Code farbig machen ?
-
Hi und Willkommen bei tutorials.de

welches Betriebssystem verwendest du eigentlich?
Zum farbigen C-Code: Statt CODE einfach CPP als Tag nehmen
[cpp]...[/cpp]
Gruß
PS: KorrekturGeändert von sheel (23.03.11 um 10:38 Uhr)
-
23.03.11 10:38 #5
- Registriert seit
- Mar 2011
- Beiträge
- 15
Momentan Win 7, aber der Code ist größtenteils portable, soll für mich dann auch einfacher auf Unix&Co implementierbar sein.
danke für den Hinweis.
Edit:
Hab die Lösung gefunden. Ich muss, nachdem ich Datenübertragung über den Datensocket beendet habe sofort die passive Verbindung beenden, d.h ich hab einfach das closesocket(sock_data) nach jeder Verbindung versäumt.
Jetzt kann ich auch wieder ohne Probleme auf den Controlport des Ftp - Servers zugreifen.
Soviel Geschreibe für so nen banalen Fehler, das war wohl das was auch posi90 erwähnt hatte, habs bloß nicht sofort erkannt.
Danke für die Hilfe, man sieht sich ;)Geändert von Eburneolus (23.03.11 um 16:09 Uhr)
Ähnliche Themen
-
Socketprogrammierung unter Linux
Von dadevelopa im Forum C/C++Antworten: 1Letzter Beitrag: 19.03.10, 13:27 -
TCP/IP Problem Socketprogrammierung
Von Winner im Forum C/C++Antworten: 6Letzter Beitrag: 10.10.07, 08:44 -
Socketprogrammierung in C
Von reavez im Forum C/C++Antworten: 9Letzter Beitrag: 23.12.05, 14:31 -
Socketprogrammierung
Von jma im Forum VisualStudio & MFCAntworten: 4Letzter Beitrag: 31.10.04, 11:57 -
Socketprogrammierung
Von Bigbutcher im Forum JavaAntworten: 2Letzter Beitrag: 14.01.04, 18:19





Zitieren

Login






