tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
4
ZUGRIFFE
758
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    Eburneolus Eburneolus ist offline Mitglied
    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)
     

  2. #2
    posi90 posi90 ist offline Mitglied Gold
    Registriert seit
    Aug 2010
    Beiträge
    113
    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
     

  3. #3
    Eburneolus Eburneolus ist offline Mitglied
    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 ?
     

  4. #4
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    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: Korrektur
    Geändert von sheel (23.03.11 um 10:38 Uhr)
     

  5. #5
    Eburneolus Eburneolus ist offline Mitglied
    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

  1. Socketprogrammierung unter Linux
    Von dadevelopa im Forum C/C++
    Antworten: 1
    Letzter Beitrag: 19.03.10, 13:27
  2. TCP/IP Problem Socketprogrammierung
    Von Winner im Forum C/C++
    Antworten: 6
    Letzter Beitrag: 10.10.07, 08:44
  3. Socketprogrammierung in C
    Von reavez im Forum C/C++
    Antworten: 9
    Letzter Beitrag: 23.12.05, 14:31
  4. Socketprogrammierung
    Von jma im Forum VisualStudio & MFC
    Antworten: 4
    Letzter Beitrag: 31.10.04, 11:57
  5. Socketprogrammierung
    Von Bigbutcher im Forum Java
    Antworten: 2
    Letzter Beitrag: 14.01.04, 18:19

Stichworte