我想创建一个脚本来在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;
}
答案 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
伪码
对于唯一文件名,我只使用了一个填充了字符winsock2.h
的字符数组。您还可以选择是否使用本地文件扩展名进行检查,并将其添加到唯一文件名的末尾:
[A-Za-z0-0]
例如,如果我们有本地string generateUniqueFilename(SOCKET _FSoc,
int port,
string remotePath,
bool useLocalFileExtension,
string localFile)
文件,则将useLocalFileExtension
设置为true
会产生具有.txt
扩展名.txt
的唯一文件名。
我的最终节目
O3xh8p939YN4hV.txt