1

winsockを使用して単純なFTPクライアントを実装しようとしています。ファイルをダウンロードしようとして問題が発生しました。現在使用しているコードは次のとおりです。

bool FTPHandler::downloadFile(const char * remoteFilePath, const char * filePath) {
    if (!isConnected()) {
         setErrorMsg("Not connected, imposible to upload file...");
         return false;
     }   

     if (usePasiveMode) {
         this->pasivePort = makeConectionPasive();
         if (this->pasivePort == -1) {
             //error msg will be setted by makeConectionPasive()
             return false;
         }
     } else {
         setErrorMsg("Unable to upload file not in pasive mode :S");
         return false;
     }

     char * fileName = new char[500];
     getFileName(remoteFilePath,fileName);     

     // Default name and path := current directory and same name as remote.
     if (filePath == NULL) {
          filePath = fileName;
     }

     if (!setDirectory(remoteFilePath)) {
         return false;
     }



    char msg[OTHER_BUF_SIZE];
    char serverMsg[SERVER_BUF_SIZE];
    sprintf(msg,"%s%s\n",RETR_MSG,fileName);
    send(sock, msg, strlen(msg), 0);

     SOCKET passSocket;
     SOCKADDR_IN passServer;

     passSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (passSocket == INVALID_SOCKET) {
         WSACleanup();  
         sprintf(errorMsg,"Error trying to create socket (WSA error code: %d)",WSAGetLastError());
         return false;
     }

     passServer.sin_family = PF_INET;
     passServer.sin_port =   htons(this->pasivePort);
     passServer.sin_addr = *((struct in_addr *)gethostbyname(this->host)->h_addr);
     memset(server.sin_zero,0,8);

     int errorCode = connect(passSocket, (LPSOCKADDR) &passServer, sizeof(struct sockaddr));
     int tries = 0;
     while (errorCode == SOCKET_ERROR) {
           tries++;
           if (tries >= MAX_TRIES) {
               closesocket(passSocket);
               sprintf(errorMsg,"Error trying to create socket");
               WSACleanup();
               return false;
           }
     }

     char * buffer = (char *) malloc(CHUNK_SIZE);
     ofstream f(filePath);

     Sleep(WAIT_TIME);
     while (int readBytes = ***recv(passSocket, buffer, CHUNK_SIZE, 0)***>0) {
           buffer[readBytes] = '\0';
           f.write(buffer,readBytes);
     }
     f.close();

     Sleep(WAIT_TIME);
     recv(sock, serverMsg, OTHER_BUF_SIZE, 0);
     if (!startWith(serverMsg, FILE_STATUS_OKEY_CODE)) {
         sprintf(errorMsg,"Bad response: %s",serverMsg);
         return false;
     }

     return true;
}

その最後のrecv()は1バイトを数回返します。その後、メソッドは終了し、約1Kbであるはずのファイルはわずか23バイトになります。

なぜrecvは穴ファイルを読み取らないのですか?

4

1 に答える 1

2

このコードには、あらゆる種類の論理ホールと不正/欠落エラー処理があります。あなたは本当に一般的にこのコードをクリーンアップする必要があります。

sizeof()に間違った値を渡しており、失敗connect()した場合にエラーを正しく処理していませconnect()ん(再試行ループは役に立ちません)。の代わりにsizeof(sockaddr_in)またはを使用する必要があります。また、正しく初期化されていません。sizeof(passServer)sizeof(sockaddr)passServer

recv()エラーをチェックしていません。recv()そして、実際にバイト数を読み取るオフチャンスでCHUCK_SIZEは、バッファオーバーフローが発生し、ヌルバイトをバッファに書き込むときにメモリが破損します(これを行う必要はありません)。これは、の境界を超えて書き込むためです。バッファ。

失敗した場合connect()、またはrecv()サーバー側で開始された切断以外のエラーで失敗した場合は、サーバーに転送を中止するように指示していません。

サーバーにパッシブモードに移行するように指示したら、RETRコマンドを送信する前に、サーバーが指示するIP /ポート(ポートだけでなく)に接続する必要があります。

サーバーにコマンドを送信することを忘れないでください。これにより、ASCIIテキストやバイナリデータTYPEなど、ファイルバイトを送信する形式がわかります。間違った形式でファイルを転送しようとすると、データが破損する可能性があります。FTPのデフォルトはASCIIであり、Binaryではありません。TYPE ATYPE ITYPE

そして最後に、ソケットを効果的にプログラムする方法を明らかに知らないように思われるので、FtpGetFile()関数など、WinSockの代わりにWinInetライブラリのFTP部分を直接使用することをお勧めします。WinInetにFTPファイルの転送の詳細を処理させます。

于 2012-07-30T21:26:33.337 に答える