将文件发送到远程 FTP 服务器

Posted

技术标签:

【中文标题】将文件发送到远程 FTP 服务器【英文标题】:Sending file to distant FTP server 【发布时间】:2021-07-06 07:28:40 【问题描述】:

我有一个任务“发送文件到远程 FTP 服务器”。我已经编写了代码,但它无法正常工作。我创建了一个用于数据传输的套接字并尝试上传我的文件。上传文件后,我想使用recv()检查服务器答案,但我的程序此时挂起,但我可以在服务器上看到我的文件。如果我从代码中删除 recv(),我的文件大小为 0 字节。这几天我一直在尝试解决这个问题。谁能帮帮我?

我正在使用这个 FTP 服务器进行测试:ftp://speedtest.tele2.net/

int upload_file(char *filename) 
    char str[256];
    char buff[1024];
    int getFile;
    int bytes_read;

    //ds - for data

    sprintf(str, "CWD %s\r\n", "upload");
    send(s, str, strlen(str), 0);
    get_server_answer();
    switch_to_passive_mode();
    sprintf(str, "TYPE I\r\n");
    send(s, str, strlen(str), 0);
    get_server_answer();
    sprintf(str, "STOR %s\r\n", filename);
    send(s, str, strlen(str), 0);
    get_server_answer();

    getFile = open(filename, O_RDONLY, 0644);
    while (1) 
        bytes_read = read(getFile, buff, 1024);
        if (bytes_read <= 0)
            break;
        send(ds, buff, bytes_read, 0);
    
    char tmp[256];
    recv(s, tmp, 256, MSG_WAITALL); // program hangs here

    close(getFile);
    close(ds);
    close(s);
    return 0;

【问题讨论】:

@SteffenUllrich 再仔细看看。大概是switch_to_passive_mode() 发送了一个PASV 命令。并且正在使用套接字s 发送命令,但正在使用不同的套接字ds 发送文件数据 @RemyLebeau:你是对的。我完全错过了这些细节。感谢您纠正我。 【参考方案1】:

默认情况下,FTP 数据传输以STREAM 传输模式运行。在该模式下,通过ds 套接字发送文件数据后,您需要关闭ds 套接字以向服务器发送文件结束信号,尝试读取服务器的答案之前(你为什么不使用get_server_answer() 代替?)。由于您没有这样做,因此您正在等待永远不会发送的最终服务器答案。

当您删除recv() 时,您将同时关闭dss 套接字。通过关闭s 套接字而不首先发送QUIT 命令,服务器会认为您的客户端在收到服务器的应答之前已经意外消失,因此中止传输。

所以,您需要:

关闭ds(但不是s!)之后你的循环完成,但之前你阅读了答案。

使用MODE命令将数据连接的传输模式切换为BLOCKCOMPRESSED模式,它们不会通过关闭数据连接来发出EOF信号。有关详细信息,请参阅RFC 959 第 3.4 节。

此外,在通过ds 发送文件数据之前,您没有验证对STOR 命令的初始回答是否成功(回复代码为125 或150)

【讨论】:

感谢您的回答,这对我很有帮助。将您的答案标记为正确

以上是关于将文件发送到远程 FTP 服务器的主要内容,如果未能解决你的问题,请参考以下文章

如何将http上的文件远程上传到ftp空间里?

FTP原理与配置

QNetworkAccessManager::put - QIODevice::read: 将文件发送到 ftp 服务器后设备未打开

能向远程主机发送cmd命令,如何使用cmd传送本机文件?

远程FTP下载文件

如何在 HTTP 请求中发送文件并通过 Mule 中的 FTP 将其上传到文件服务器