2016-11-26 45 views
0

我想创建一个脚本在ftp服务器上发送一个名为office-data.txt的文件,但我希望这个脚本,当文件发送时到FTP服务器,必须随机更改其名称,只能远程更改。例如,每次脚本启动时,office-data-12478.txt或office-data-22478.txt和随机生成的名称都不能相同。发送到FTP服务器时如何更改文件名?Dev-C++通过ftp发送一个文件的随机文件名

#include <string> 
#include <winsock.h> 
#include <windows.h> 
#include <sstream> 
#include <iostream> 
#include <stdio.h> 
#include <cstdlib> 

using namespace std; 

void stringtoint(const string &s, int &i){ 
    istringstream myStream(s); 
    myStream>>i; 
} 

void sendLogIn(SOCKET _LSoc){ 
char userbuffer[] = "username";     
char passbuffer[] = "password";     
char username[] = "USER "; 
char password[] = "PASS "; 
char servermessage[1000]; 

strcat(username, userbuffer); 
strcat(username, "\r\n"); 

send(_LSoc, username, strlen(username), 0); 
Sleep(1000); 
    recv(_LSoc, servermessage, 1000, 0); 

strcat(password, passbuffer); 
strcat(password, "\r\n"); 

send(_LSoc, password, strlen(password), 0); 
Sleep(1000); 
    recv(_LSoc, servermessage, 1000, 0); 
} 

int sendConnInfo(SOCKET _CSoc){ 
char servermessage[10000]; 
char ftpmessage[50]; 
string message; 
string portbuffer; 
    string port1; 
string port2; 
size_t position; 
size_t position2; 
int port; 
int portbuf; 
int _portbuf; 

send(_CSoc, "TYPE I\r\n", 8, 0); 
Sleep(1000); 
    recv(_CSoc, servermessage, 10000, 0); 
Sleep(1000); 
Sleep(1000); 
    send(_CSoc, "PASV\r\n", 6, 0); 
Sleep(1000); 
    recv(_CSoc, ftpmessage, 50, 0); 

message = ftpmessage; 
position = message.find("Mode"); 
portbuffer = message.substr(position+21); 

    position = portbuffer.find(","); 
    position2 = portbuffer.find(">"); 

    port1 = portbuffer.substr(0, position); 
    port2 = portbuffer.substr(position+1, position2-1); 

    stringtoint(port1, portbuf); 
    stringtoint(port2, _portbuf); 

    port = portbuf*256; 
    port = port + _portbuf; 
    return port; 
} 

void sendFileRequest(SOCKET _FSoc){ 
    send(_FSoc, "STOR test.txt\r\n", strlen("STOR test.txt\r\n"), 0); 
    Sleep(1000); 
} 

BOOL ftpSocket(int port){ 
    SOCKET sock; 
    SOCKADDR_IN pasvserver; 
    char servermessage[MAX_PATH]; 
    HANDLE HFile; 
    DWORD read; 
    char *buffer; 
    char filename[] = "C:\\test.txt"; 
    int connectionerror2; 
    int trycount2 = 2;  

    sock = socket(2, SOCK_STREAM, IPPROTO_TCP); 
    if(sock == INVALID_SOCKET){ 
    WSACleanup(); 
    return 0; 
    } 

pasvserver.sin_family = 2; 
pasvserver.sin_port = htons(port);         
pasvserver.sin_addr.s_addr = inet_addr("66.220.9.50");   //Once again the drivehq ftp server 

connectionerror2 = connect(sock, (LPSOCKADDR)&pasvserver, sizeof(struct sockaddr)); 
    while(connectionerror2 == SOCKET_ERROR){ 
      connectionerror2 = connect(sock, (LPSOCKADDR)&pasvserver, sizeof(struct sockaddr)); 
      trycount2++; 
      if(trycount2 = 10){ 
         closesocket(sock); 
         WSACleanup(); 
         return 0; 
      } 
    } 


    HFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 

    buffer = (char *)malloc(4096); 
    SetFilePointer(HFile, 0, NULL, FILE_BEGIN); 

    while(ReadFile(HFile, buffer, 4096, &read, NULL) && read > 0){ 
     send(sock, buffer, read, 0); 
    } 

    return true; 
} 


int sendFile(){ 
FreeConsole(); 
WSAData WData; 
SOCKET FSoc; 
SOCKADDR_IN server; 
int connectionerror; 
int trycount = 2; 
char servermessage[MAX_PATH]; 
int port; 


WSAStartup(MAKEWORD(2,2), &WData); 
FSoc = socket(2, SOCK_STREAM, IPPROTO_TCP); 
     if(FSoc == INVALID_SOCKET){ 
    WSACleanup(); 
    return 0; 
    } 

server.sin_family = 2; 
server.sin_port = htons(21); 
server.sin_addr.s_addr = inet_addr("66.220.9.50"); //this is the drivehq ftp server address. 


connectionerror = connect(FSoc, (LPSOCKADDR)&server, sizeof(struct sockaddr)); 
    while(connectionerror == SOCKET_ERROR){ 
      connectionerror = connect(FSoc, (LPSOCKADDR)&server, sizeof(struct sockaddr)); 
      trycount++; 
      if(trycount = 10){ 
         closesocket(FSoc); 
         WSACleanup(); 
         return 0; 
      } 
    } 

recv(FSoc, servermessage, sizeof(servermessage),0); 

sendLogIn(FSoc); 
Sleep(1000); //give the server and the client sometime to deal with the influx of new messages 
       //so that data for the ip doesnt get mixed up. 
    port = sendConnInfo(FSoc); 
    sendFileRequest(FSoc); 
    ftpSocket(port); 
    WSACleanup(); 
    return 0; 
} 
int main(){ 
    sendFile(); 
    return 1; 
} 
+0

粘贴代码时,请多加小心。但是,您应该注意[SO]不是代码写入服务。 –

回答

1

首先,我建议你停止使用Dev-C++.这实在是不合时宜,以及最新的测试版本是超过10年前出版:

February 21th 2005 : Dev-C++ 5 Beta 9.2 (4.9.9.2) released !

你应该从Cygwin尝试NetBeans C/C++捆绑和编译器/链接器(gcc/g ++/make)。有关如何设置此类开发环境的更多信息,请查看此链接here。你也可以尝试Eclipse CDT甚至Visual Studio Express或最新的Visual Studio Community

现在为您的程序和代码。

尽管您的程序能够正常工作,但我发现了一些小错误,这些错误在编译并运行时无法正常工作。

您想要将文件上传到FTP服务器,并使用唯一的文件名将其保存到远程路径。

您可以简单地使用STOU ftp命令而不是STOR,ftp服务器将在当前工作目录下以唯一文件名保存该文件。因此,您必须更改sendFileRequest过程才能使用CWD将目录切换到我们要保存文件的目录,然后仅使用STOU而不带任何参数,服务器将处理剩下的文件并使用唯一的文件名进行保存。例如,Pure-FTP服务器生成一个像这样的文件名pureftpd.583c3777.dd.0000

sendFileRequest过程会变成这个样子:

void sendFileRequest(SOCKET _FSoc){ 
    char cwdCmd[MAX_PATH] = "CWD /web/share/tmp/\r\n"; 
    send(_FSoc, cwdCmd, strlen(cwdCmd), 0); 
    Sleep(1000); 

    //char stor[] = "STOR /web/share/tmp/test.txt\r\n"; 
    char stor[] = "STOU\r\n"; 
    send(_FSoc, stor, strlen(stor), 0); 
    Sleep(1000); 
} 

当心,一些FTP服务器不支持STOU命令。

现在,如果您想控制文件名并根据某些条件生成名称,则必须读取要上载文件的目录中的文件列表,然后生成一个唯一的文件名存在于远程目录的文件列表中。

我们想发出一个ftp命令来获取当前目录的文件名。 NLST ftp命令是我们想要的,因为它发送包含文本数据的缓冲区,并为每个文件使用换行符分隔符;在当前工作目录中的所有文件/文件夹名称(只有文件名,没有更多数据)的列表。我们还需要使用被动模式打开数据连接来检索数据。另外我也注意到,尽管文件是使用远程服务器路径的唯一名称创建的,但根本没有传输数据。发生这种情况是因为我非常快地执行程序,并且之前的ftp会话没有用QUIT命令正确关闭。当我在过程结束时添加QUIT命令时,所有零数据文件传输问题都消失了。

代码级问题和言论

  • 我已经改变TYPE I图像/二进制TYPE A文本,因为大多数的FTP服务器做修复从UNIX传送文本文件时,Windows格式,副行饲料CR LF反之亦然。

  • 您必须始终通过使用shutdown和/或closesocket关闭数据套接字连接来关闭数据连接,否则服务器可能会中止传输的数据。

  • 你有一个功能转换到std::string整数,但你也可以使用std::stoi如果你告诉编译器使用-std=c++11选项,使用C++ 11标准。

  • 当您使用recv读取服务器响应,你必须总是空使用recv返回值终止响应缓冲区串,或仅处理字节recv回报的多少。

  • 该程序没有状态读取行为,这可能会导致很多错误和完全失败。正确的ftp应用程序行为必须始终取决于服务器发送到命令连接的响应。例如,如果ftp服务器达到了最大客户端限制,那么你的程序就不会知道,并且将继续发出命令直到它失败或结束。如果发生这种错误,程序不应该也不能继续。

编译器选项

-std=c++11std::stoi

连接器选项

-lws2_32以包括用于winsock2.h

需要在cygwin

伪代码

  • 初始化ftp server命令连接
  • 发送FTP登录信息
  • 生成唯一的文件名
    • 读取远程目录文件名
    • 生成随机的名字,直到我们不” t名称为文件列表
  • 与唯一的文件名的文件发送到服务器

对于唯一的文件名,我只是用充满字符[A-Za-z0-0]一个字符数组。您也可以选择,如果你会使用本地文件扩展名进行检查,并把它添加到唯一的文件名的末尾:

string generateUniqueFilename(SOCKET _FSoc, 
           int port, 
           string remotePath, 
           bool useLocalFileExtension, 
           string localFile) 

例如,设置useLocalFileExtensiontrue当我们有一个本地.txt文件,将结果具有.txt分机O3xh8p939YN4hV.txt的唯一文件名。

我的最终方案

#include <winsock2.h> 
#include <windows.h> 
#include <sstream> 
#include <iostream> 
#include <stdio.h> 
#include <cstdlib> 
#include <cstdio> 
#include <algorithm> 
#include <vector> 


#define REMOTE_FTP_HOST_IP "x.x.x.x" 
#define REMOTE_FTP_USERNAME "username"    
#define REMOTE_FTP_PASSWORD "password" 

#define ECHO_FTP_RESPONSE 1 // Set to 0 to disable ftp responses output 

using namespace std; 


// Declarations --------------------------------------------------- 

void echoResponse(string); 
void echoResponse(LPSTR); 
void recvResponseAndEcho(SOCKET, LPSTR, int); 
void recvResponseAndEcho(SOCKET); 
string generateRandomFilename(int); 
int readSocketData(int, LPSTR, int); 
string generateUniqueFilename(SOCKET, int, string, bool, string); 
void sendLogIn(SOCKET socket); 
void sendFileRequest(SOCKET, string, string); 
void sendTypeICmd(SOCKET); 
void sendTypeACmd(SOCKET); 
int sendPasvCmd(SOCKET); 
void sendQuitCmd(SOCKET); 
BOOL ftpSocket(string, int); 
int sendFile(string, string); 


// Program entry point -------------------------------------------- 

int main(){ 
    sendFile("C:\\test.txt", "/remote/ftp/path/"); 
    return EXIT_SUCCESS; 
} 

void echoResponse(string response) { 
    if(ECHO_FTP_RESPONSE) { 
     string respclean = response.erase(response.find_last_not_of(" \t\n\r") + 1); 
     cout << respclean << endl; 
    } 
} 

void echoResponse(LPSTR response) { 
    if(ECHO_FTP_RESPONSE) { 
     string respstr = response; 
     echoResponse(respstr); 
    } 
} 

void recvResponseAndEcho(SOCKET socket, LPSTR buffer, int bufsize) { 
    int nread = recv(socket, buffer, bufsize, 0); 
    *(buffer + nread) = 0; 
    echoResponse(buffer); 
} 

void recvResponseAndEcho(SOCKET socket) { 
    char srvResponse[4096]; 
    recvResponseAndEcho(socket, (LPSTR)&srvResponse, sizeof(srvResponse)); 
} 

// Generate o random filename using an array of charactres [A-Za-z0-9] 
string generateRandomFilename(int length) { 
    string rndFilename; 
    char fileChars[] = 
      "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
      "abcdefghijklmnopqrstuvwxyz" 
      ""; 
    int fileCharsLength = strlen(fileChars); 

    srand(time(NULL)); 

    for(int i = 0; i < length; i++) 
     rndFilename += fileChars[rand() % fileCharsLength]; 

    return rndFilename; 
} 

int readSocketData(int port, LPSTR buffer, int buffer_size) { 
    SOCKET sock; 
    SOCKADDR_IN pasvserver; 
    int connectionerror2; 
    int trycount2 = 2; 

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if(sock == INVALID_SOCKET){ 
     WSACleanup(); 
     return 0; 
    } 

    pasvserver.sin_family = AF_INET; 
    pasvserver.sin_port = htons(port);         
    pasvserver.sin_addr.s_addr = inet_addr(REMOTE_FTP_HOST_IP); 

    connectionerror2 = connect(sock, (LPSOCKADDR)&pasvserver, sizeof(struct sockaddr)); 
    while(connectionerror2 == SOCKET_ERROR){ 
     connectionerror2 = connect(sock, (LPSOCKADDR)&pasvserver, sizeof(struct sockaddr)); 
     trycount2++; 
     if(trycount2 = 10) { 
      closesocket(sock); 
      WSACleanup(); 
      return 0; 
     } 
    } 

    int result = recv(sock, buffer, buffer_size, 0); 
    shutdown(sock, SD_BOTH); 
    closesocket(sock); 
    return result; 
} 

string generateUniqueFilename(SOCKET _FSoc, int port, string remotePath, bool useLocalFileExtension, string localFile) { 
    string newFilename; 
    char cwd[MAX_PATH]; 
    char cmd[7] = "NLST\r\n"; 
    char listFilesBuffer[4096]; 
    char servermessage[2048]; 
    int listFilesBufferReadLength; 

    strcpy(cwd, "CWD "); 
    strcat(cwd, remotePath.c_str()); 
    strcat(cwd, "\r\n"); 
    send(_FSoc, cwd, strlen(cwd), 0); 
    Sleep(1000); 

    recvResponseAndEcho(_FSoc, (LPSTR)&servermessage, sizeof(servermessage)); 
    Sleep(1000); 

    send(_FSoc, cmd, strlen(cmd), 0); 
    listFilesBufferReadLength = readSocketData(port, listFilesBuffer, 4096); 

    if(listFilesBufferReadLength > 0) { 
     std::istringstream fileLines(listFilesBuffer); 
     string fileLine, localFileExtension; 
     std::vector<std::string> filesList; 

     while (std::getline(fileLines, fileLine)) { 
      // Trim whitespaces from each line 
      fileLine = fileLine.erase(fileLine.find_last_not_of(" \t\n\r") + 1); 
      if(fileLine != "." && fileLine != "..") 
       // Save to a vector or strings if it's not current and level up directory 
       filesList.push_back(fileLine); 
     } 

     if(useLocalFileExtension) { 
      int dotPos = localFile.find_last_of("."); 
      localFileExtension = dotPos > 0 ? localFile.substr(dotPos) : ""; 
     } 

     vector<string>::iterator fileFind; 

     do { 
      // Generate random filenames of 14 characters length 
      // untill the filename does not exist on the remote FTP server path 
      newFilename = generateRandomFilename(14); 
      if(useLocalFileExtension) 
       newFilename += localFileExtension; 
     } while((fileFind = std::find(filesList.begin(), filesList.end(), newFilename)) != filesList.end()); 
    } 

    return newFilename; 
} 

void sendLogIn(SOCKET socket) {    
    char userCmd[128] = "USER "; 
    char passCmd[128] = "PASS "; 

    strcat(userCmd, REMOTE_FTP_USERNAME); 
    strcat(userCmd, "\r\n"); 
    send(socket, userCmd, strlen(userCmd), 0); 
    recvResponseAndEcho(socket); 

    strcat(passCmd, REMOTE_FTP_PASSWORD); 
    strcat(passCmd, "\r\n"); 
    send(socket, passCmd, strlen(passCmd), 0); 
    recvResponseAndEcho(socket); 
} 

void sendFileRequest(SOCKET socket, string remoteDirectory, string storFilename) { 
    char cwdCmd[MAX_PATH] = "CWD "; 
    char storCmd[MAX_PATH] = "STOR "; 
    //char stouCmd[] = "STOU\r\n"; 

    // Change current working directory 
    strcat(cwdCmd, remoteDirectory.c_str()); 
    strcat(cwdCmd, "\r\n"); 
    send(socket, cwdCmd, strlen(cwdCmd), 0); 
    Sleep(1000); 
    recvResponseAndEcho(socket); 

    // Send stor ftp command 
    strcat(storCmd, storFilename.c_str()); 
    strcat(storCmd, "\r\n"); 
    send(socket, storCmd, strlen(storCmd), 0); 

    // Send stou ftp command insted of stor 
    //send(socket, stouCmd, strlen(stouCmd), 0); 
} 


// Image/binary type 
void sendTypeICmd(SOCKET socket) { 
    char typeCmd[] = "TYPE I\r\n"; 
    send(socket, typeCmd, strlen(typeCmd), 0); 
    Sleep(1000); 
    recvResponseAndEcho(socket); 
} 

// Text type 
void sendTypeACmd(SOCKET socket) { 
    char typeCmd[] = "TYPE A\r\n"; 
    send(socket, typeCmd, strlen(typeCmd), 0); 
    Sleep(1000); 
    recvResponseAndEcho(socket); 
} 

int sendPasvCmd(SOCKET socket) { 
    int result = -1; 
    char pasvCmd[] = "PASV\r\n"; 
    char srvResponse[4096]; 

    send(socket, pasvCmd, strlen(pasvCmd), 0); 
    Sleep(1000); 
    recvResponseAndEcho(socket, (LPSTR)&srvResponse, sizeof(srvResponse)); 

    // Read the pasv response, something like: 
    // 227 Entering Passive Mode (x,x,x,x,y,y) 
    // where x are the ip bytes and y are the port bytes 
    string pasvMessage = srvResponse; 
    int modeStart = pasvMessage.find("Mode"); 

    if(modeStart > 0) { 
     int parenthesisStart = pasvMessage.find("(", modeStart); 
     if(parenthesisStart > 0) { 
      string currentPasvByte; 
      char currentChar; 
      int currentCharPos = parenthesisStart, 
       currentPasvByteIndex = 0, 
       highByte = -1, 
       lowByte = -1; 

      do { 
       currentChar = pasvMessage[++currentCharPos]; 
       if(currentChar == ',' || currentChar == ')') { 
        if(currentPasvByteIndex == 4) 
         highByte = stoi(currentPasvByte); 
        else if(currentPasvByteIndex == 5) 
         lowByte = stoi(currentPasvByte); 
        currentPasvByteIndex++; 
        currentPasvByte = ""; 
       } else 
        currentPasvByte += currentChar; 
      } while(currentChar != ')'); 

      // Assemble the port number by joing hi and lo port number bytes 
      if(highByte != -1 && lowByte != -1) 
       result = (highByte << 8) | lowByte; 
     } 
    } 
    return result; 
} 

void sendQuitCmd(SOCKET socket) { 
    char quitCmd[] = "QUIT\r\n"; 
    send(socket, quitCmd, strlen(quitCmd), 0); 
    recvResponseAndEcho(socket); 
} 

BOOL ftpSocket(string localFile, int port) { 
    BOOL result = false; 
    SOCKET sock; 
    SOCKADDR_IN pasvserver; 
    int connectionerror2; 
    int trycount2 = 2; 

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if(sock == INVALID_SOCKET){ 
     WSACleanup(); 
     return 0; 
    } 

    pasvserver.sin_family = AF_INET; 
    pasvserver.sin_port = htons(port);         
    pasvserver.sin_addr.s_addr = inet_addr(REMOTE_FTP_HOST_IP); //Once again the drivehq ftp server 

    connectionerror2 = connect(sock, (LPSOCKADDR)&pasvserver, sizeof(struct sockaddr)); 
    while(connectionerror2 == SOCKET_ERROR){ 
     connectionerror2 = connect(sock, (LPSOCKADDR)&pasvserver, sizeof(struct sockaddr)); 
     trycount2++; 
     if(trycount2 = 10) { 
      closesocket(sock); 
      WSACleanup(); 
      return false; 
     } 
    } 

    HANDLE hFile = CreateFile(localFile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);; 

    if(hFile != INVALID_HANDLE_VALUE) { 
     DWORD read; 
     char buffer[4096]; 
     SetFilePointer(hFile, 0, NULL, FILE_BEGIN); 

     while(ReadFile(hFile, buffer, 4096, &read, NULL) && read > 0) { 
      send(sock, buffer, read, 0); 
     } 

     CloseHandle(hFile); 
     result = true; 
    } 

    shutdown(sock, SD_BOTH); 
    closesocket(sock); 
    return result; 
} 

int sendFile(string localFile, string remotePath) { 
    FreeConsole(); 
    WSAData WData; 
    SOCKET FSoc; 
    SOCKADDR_IN server; 
    int connectionerror; 
    int trycount = 2; 
    int port; 

    WSAStartup(MAKEWORD(2,2), &WData); 
    FSoc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if(FSoc == INVALID_SOCKET){ 
     WSACleanup(); 
     return 0; 
    } 

    server.sin_family = AF_INET; 
    server.sin_port = htons(21); 
    server.sin_addr.s_addr = inet_addr(REMOTE_FTP_HOST_IP); //this is the drivehq ftp server address.              

    connectionerror = connect(FSoc, (LPSOCKADDR)&server, sizeof(struct sockaddr)); 
    while(connectionerror == SOCKET_ERROR){ 
     connectionerror = connect(FSoc, (LPSOCKADDR)&server, sizeof(struct sockaddr)); 
     trycount++; 
     if(trycount = 10){ 
      closesocket(FSoc); 
      WSACleanup(); 
      return 0; 
     } 
    } 

    recvResponseAndEcho(FSoc); 

    sendLogIn(FSoc); 
    Sleep(1000); //give the server and the client sometime to deal with the influx of new messages 
    //so that data for the ip doesnt get mixed up. 

    // Send typea command to transfer text data. 
    // It works better for windows to unix text files transfer, bacause it fixes 
    // the line endnings CR, LF on most ftp servers 
    // Use typei command for binary data. 
    //sendTypeACmd(FSoc); 
    sendTypeACmd(FSoc); 

    // Open passing mode for the files list data 
    port = sendPasvCmd(FSoc); 

    // Generate a unique filename that does not exists on the FTP remote directory 
    string filename = generateUniqueFilename(FSoc, port, remotePath, true, localFile); 

    // Open passing mode for the file transfer data 
    port = sendPasvCmd(FSoc); 

    sendFileRequest(FSoc, remotePath, filename); 
    ftpSocket(localFile, port); 
    recvResponseAndEcho(FSoc); 

    sendQuitCmd(FSoc); 
    shutdown(FSoc, SD_BOTH); 
    closesocket(FSoc); 
    WSACleanup(); 
    return 0; 
}