Dev-c ++使用随机文件名通过ftp发送文件

时间:2016-11-26 12:26:16

标签: random upload ftp filenames dev-c++

我想创建一个脚本来在ftp服务器上发送一个名为office-data.txt的文件,但我希望这个脚本在文件发送到FTP服务器时,必须随机改变它的名字,只能远程。例如,office-data-12478.txt或office-data-22478.txt以及随机生成的名称在每次脚本启动时都不能相同。如何在将文件名发送到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;
}

1 个答案:

答案 0 :(得分:1)

首先,我建议你停止使用Dev-C++.它已经过时了,最新的测试版发布于10多年前了:

  

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

你应该从NetBeans C/C++尝试Cygwin bundle和编译器/链接器(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转换为整数的函数,但如果您告诉编译器使用 C ++ 11 ,您也可以使用std::stoi标准使用-std=c++11选项。

  • 使用recv读取服务器响应时,必须始终使用recv返回值来终止响应缓冲区字符串,或者只处理字节数{{1} } return。

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

编译器选项

recv

-std=c++11

链接器选项

std::stoi包含-lws2_32所需的cygwin libws2_32.a

伪码

  • 初始化ftp服务器命令连接
  • 发送ftp登录信息
  • 生成唯一的文件名
    • 读取远程目录文件名
    • 生成随机名称,直到我们没有文件列表的名称
  • 将具有唯一文件名的文件发送到服务器

对于唯一文件名,我只使用了一个填充了字符winsock2.h的字符数组。您还可以选择是否使用本地文件扩展名进行检查,并将其添加到唯一文件名的末尾:

[A-Za-z0-0]

例如,如果我们有本地string generateUniqueFilename(SOCKET _FSoc, int port, string remotePath, bool useLocalFileExtension, string localFile) 文件,则将useLocalFileExtension设置为true会产生具有.txt扩展名.txt的唯一文件名。

我的最终节目

O3xh8p939YN4hV.txt