【问题标题】:425 Can't open data connection on my program whereas Filezilla work425 Filezilla 工作时无法在我的程序上打开数据连接
【发布时间】:2014-10-17 12:12:32
【问题描述】:

我尝试制作一个以活动模式上传文件的 FTP 客户端(C++ 与 linux 的套接字库)。 当我想在本地服务器(LAN)上发送文件时,我的程序可以工作,但它 当我想在远程服务器(WAN)上发送文件时不起作用。 我有错误 425 无法打开数据连接。我做了很多研究 通常这个问题来自 NAT(它可能被阻止 数据连接端口)。但我已经尝试使用 Filezilla(处于活动模式)并且它有效。 所以我没找到数据连接的问题在哪里。

这是我的代码:

using namespace std;
int sock;
int sock_data,new_sock;
struct sockaddr_in sin_data;
struct sockaddr_in cli_addr = {0};

char* receiving(int socket)
{
    char message[1000] = {'/0'};
    recv(socket,message,sizeof(message),0);
    cout << message << endl;
    return message;
}

void *send_data(void* args)
{
    send(sock,"STOR fichier.txt\r\n",sizeof("STOR fichier.txt\r\n"),0);
    receiving(sock);
    return(0);
}

void *accept_data_connexion(void* args)
{
    sock_data = socket(AF_INET,SOCK_STREAM,6);
    sin_data.sin_family = AF_INET;
    sin_data.sin_port = htons(58703);
    sin_data.sin_addr.s_addr = INADDR_ANY;
    socklen_t clilen = sizeof(cli_addr);
    new_sock = accept(sock_data,(struct sockaddr *)&cli_addr,&clilen);
    if(errno == 0)
        {
        cout << "Data connection is established" << endl;
        }
}

int main()
{
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(21);
    sin.sin_addr.s_addr = inet_addr("xxx,xxx,xxx,xxx");
    sock = socket(AF_INET,SOCK_STREAM,6);
    //connection
    connect(sock,(struct sockaddr *)&sin,sizeof(sin));
    receiving(sock);
    receiving(sock);
    print_box();
    //log in
    send(sock,"USER username\r\n",sizeof("USER username\r\n"),0);
    receiving(sock);
    send(sock,"PASS password\r\n",sizeof("PASS password\r\n"),0);
    receiving(sock);

    send(sock,"SYST\r\n",sizeof("SYST\r\n"),0);
    receiving(sock);
    send(sock,"PWD\r\n",sizeof("PWD\r\n"),0);
    receiving(sock);
    send(sock,"PORT xxx,xxx,xxx,xxx,229,79",sizeof("PORT xxx,xxx,xxx,xxx,229,79"),0);
    receiving(sock);
    send(sock,"TYPE I \r\n",sizeof("TYPE I \r\n"),0);
    receiving(sock);

    pthread_t th1, th2;
    void *ret;
    pthread_create (&th1,NULL, accept_data_connexion,(void*)1);
    pthread_create (&th2, NULL, send_data,(void *)2);
    (void)pthread_join (th1, &ret);
    (void)pthread_join (th2, &ret);

    ifstream fichier("fichier.txt");
    int i = 0;
    while(fichier.eof() == false)
     {
        fichier.seekg(i,fichier.beg);
        char* buffer= new char[1];
        fichier.read(buffer,1);
        write(new_sock,buffer,1);
        i++;
     }

    fichier.close();
    close(new_sock);
    close(sock_data);
    close(sock);
    return 0;
}

【问题讨论】:

  • 您可以使用wireshark等流量捕获工具来查看其他客户端向服务器发送的命令。

标签: c++ sockets upload ftp


【解决方案1】:

根本问题是accept_data_connexion()在调用accept()接收数据连接之前并没有调用bind()listen()来实际打开数据端口。

您所展示的总体上是一个糟糕的实现。你犯了很多错误。滥用sizeof()。套接字 API 和 FTP 协议都缺乏错误处理。内存泄漏。在不需要的地方使用线程。你真的需要退后一步,想想你在做什么。要么从头开始重新编写此代码以正确执行操作,要么使用为您处理细节的第三方库,例如libcurl

【讨论】:

  • 抱歉,我在发送问题之前不小心删除了 bind() 和 listen() 方法。我在这里纠正它。 pastebin.com/wiSctWC2我的目的是在处理细节之前制作一个功能程序。我不明白为什么不需要线程。当我们向服务器发送 PORT 命令时,他不会直接建立连接,而是等待类似 STOR 的命令。当我发出 STOR 命令时,FTP 服务器想在我的程序上建立连接。所以我的程序监听一个端口并同时发送命令 STOR。这就是我使用线程的原因。我错了吗?
  • 你不需要线程。使用bind/listen 打开端口并发送PORT,但不要调用accept。然后发送STOR,如果服务器回复125或150则调用accept()。如果服务器没有连接,则在一段时间后超时accept()并发送ABOR
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多