Eburneolus
Grünschnabel
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:

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:
C:
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 ================================================== */
C:
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():
C:
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():
C:
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.
Zuletzt bearbeitet: