C++ 如何在嵌入式设备上设置FTP客户端连接?

C++ 如何在嵌入式设备上设置FTP客户端连接?,c++,c,ftp,stm32,mbed,C++,C,Ftp,Stm32,Mbed,我为一个mbed项目编写FTP脚本。我与B-L475E-IOT01A开发板合作,尝试将文件发送到FTP服务器。因此,我无法使用此库与服务器建立连接。 不幸的是,客户机没有像它应该工作的那样工作。 我试图建立这样的联系: bool FTPClient::open(const char* ip_addr, int port, const char* user, const char* pass) { SocketAddress ftpAddress(ip_addr, port);

我为一个mbed项目编写FTP脚本。我与B-L475E-IOT01A开发板合作,尝试将文件发送到FTP服务器。因此,我无法使用此库与服务器建立连接。 不幸的是,客户机没有像它应该工作的那样工作。 我试图建立这样的联系:

bool FTPClient::open(const char* ip_addr, int port, const char* user, const char* pass)
{
    SocketAddress ftpAddress(ip_addr, port);

    //Connect to SocketAddress while using FTP Clients Network interface
    FTPClientControlSock.open(p_network);
    if (FTPClientControlSock.connect(ftpAddress) < 0) {
        printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
        return false;
    }

    //recieve ftp server message
    if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
        printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
        return false;
    }

    //prove ftp server message equals ftp server information messages (starting with not logged in code 220)
    if (strncmp(p_ftp_buf, "220", 3) != 0) {
        printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
        return false;
    }

    //store user info in ftp communication and send it
    sprintf(p_ftp_buf, "USER %s\r\n", user);
    printf("%s", p_ftp_buf);
    FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));

    //recieve ftp server info and print it
    if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
        printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
        return false;
    }
    printf("%s", p_ftp_buf);

    //prove ftp server message equals ftp server information messages (begin with code 331)
    if (strncmp(p_ftp_buf, "331", 3) != 0) {
        printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
        return false;
    }

    //store password in string and send it to server
    sprintf(p_ftp_buf, "PASS %s\r\n", pass);
    printf("%s", p_ftp_buf);
    FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));

    //recieve ftp server info and print it
    if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
        printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
        return false;
    }

    //check login was successful
    if (strncmp(p_ftp_buf, "230", 3) != 0) {
        printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
        return false;
    }

    printf("%s", p_ftp_buf);
    return true;
}

我真的不知道我的错误在哪里。我希望成功登录并与ftp服务器进行清晰的通信。你能帮我吗?

朱利安,服务器的所有响应都遵循一种模式。。您需要等待来自服务器的
\r\n
序列。您需要过滤TELNET协议转义序列(以字节0xff或0xfe开头,我记不清了),代码必须始终位于行的开头。此外,带有
-
而不是空格的数字表示消息较大,您应该期待另一行(每条消息的最后一行都有一个数字代码,后面跟一个空格)

这对于保持您与服务器的同步非常重要。。。。或者,您将开始收到不同于您所认为的命令的响应

从输出中不清楚您试图做什么,因为您只显示服务器的登录部分

您的命令行还可以(协议强制要求)按顺序结束
\r\n
(按该顺序)您无法执行其他操作,或者您可以访问不理解您的服务器


检查ftp协议如何工作的详细信息。传输通常在一个新的、不同的TCP连接中处理,因此您通常必须管理控制连接以及与之并行运行的一系列数据传输。

好的,我终于建立了连接。同步服务器和客户端是正确的。此外,我需要不时释放缓冲区,现在输出不再那么混乱。这是我的密码:

bool FTPClient::open(const char *ip_addr, int port, const char *user,
                 const char *pass) {


// Convert into SocketAddress
  SocketAddress ftpAddress(ip_addr, port);

  // Close FTP connection if open
  if (_ctr_open) {
    FTPClientControlSock.close();
  }

  // Connect to SocketAddress while using FTP Clients Network interface
  FTPClientControlSock.open(p_network);
  if (FTPClientControlSock.connect(ftpAddress) < 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }

  // set connection to true
  _ctr_open = true;

  // recieve ftp server messages and print if correct
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }
  if (strncmp(p_ftp_buf, "220", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    printf("%s", p_ftp_buf);
    _login = false;
  }
  wait_us(2000000);
  memset(p_ftp_buf, 0, strlen(p_ftp_buf));

  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }
  if (strncmp(p_ftp_buf, "220", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    printf("%s", p_ftp_buf);
    _login = false;
  }
  wait_us(2000000);
  memset(p_ftp_buf, 0, strlen(p_ftp_buf));

  // store user info in ftp communication print and send it
  sprintf(p_ftp_buf, "USER %s\r\n", user);
  FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));

  // recieve ftp server message and print if correct
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }
  if (strncmp(p_ftp_buf, "331", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    printf("%s", p_ftp_buf);
    _login = false;
  }
  wait_us(2000000);
  memset(p_ftp_buf, 0, strlen(p_ftp_buf));

  // store password in string and send it to server
  sprintf(p_ftp_buf, "PASS %s\r\n", pass);
  FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
  wait_us(2000000);

  // recieve ftp server info and print it
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("LINE: %d\r\n", __LINE__);
    printf("%s", p_ftp_buf);
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    wait_us(3000000);
    printf("%s", p_ftp_buf);
  }
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("LINE: %d\r\n", __LINE__);
    printf("%s", p_ftp_buf);
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    wait_us(3000000);
    printf("%s", p_ftp_buf);
  }

  // check login was successful
  if (strncmp(p_ftp_buf, "230", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }

  memset(p_ftp_buf, 0, strlen(p_ftp_buf));
  _login = true;
  return true;
}

谢谢您的帮助。

您的输出看起来很奇怪,特别是以“is now”开头的行,它没有状态代码(我还希望您的“PASS”打印在“331”之后)。您可能希望为打印添加前缀和后缀以查看边界。假设您上一次的
recv
得到了所有这些信息,那么服务器或套接字库似乎出现了某种故障并重复了以前的数据。@Hasturkun,他还可以依次发送用户XXX和传递yyy,然后接收这两条消息。。。。这不是服务器和客户机之间的通信问题,而是如何解释客户机记录的输出。。。。您可以批量发送多个命令,因为每个命令都有FTP协议的响应。@LuisColorado:没错,但他的代码会逐个处理这些命令(并以相同的顺序打印),这就是为什么我认为输出是奇怪的(一个命令的“PASS”和“331”相反)。我要说的是,代码非常乐观地认为
recv
一次返回所有内容,并且假设字符串以NUL结尾(它们可能不是,这可能是输出重复的原因)。@Hasturkun,字符串将以
\0
结尾,或者它们将不是字符串。不在C语言中。通常使用
getchar()
并正确解析输入,通常会得到格式良好的字符串,由三位代码分隔,后跟-或空格,然后是消息字符串,以CRLF序列结尾。如果您使用
read(2)
读取,那么您有一个字符数组,不以
\0
结尾,但是如果您使用
getchar()
读取,那么您需要自己添加
\0
以将该对象视为字符串。您还需要解析TELNET转义序列。@LuisColorado:谢谢,我知道C字符串是如何工作的。关键是
recv()
不会为您终止阅读内容。感谢您的快速帮助。不幸的是,我对嵌入式编程还不熟悉。你是对的:目前还不清楚我想做什么。我想把我用这个板创建的文件放到FTP服务器上。但到目前为止,我只是尝试连接,所以我不知道put函数是否有问题。如何等待\r\n结束序列?
bool FTPClient::open(const char *ip_addr, int port, const char *user,
                 const char *pass) {


// Convert into SocketAddress
  SocketAddress ftpAddress(ip_addr, port);

  // Close FTP connection if open
  if (_ctr_open) {
    FTPClientControlSock.close();
  }

  // Connect to SocketAddress while using FTP Clients Network interface
  FTPClientControlSock.open(p_network);
  if (FTPClientControlSock.connect(ftpAddress) < 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }

  // set connection to true
  _ctr_open = true;

  // recieve ftp server messages and print if correct
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }
  if (strncmp(p_ftp_buf, "220", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    printf("%s", p_ftp_buf);
    _login = false;
  }
  wait_us(2000000);
  memset(p_ftp_buf, 0, strlen(p_ftp_buf));

  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }
  if (strncmp(p_ftp_buf, "220", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    printf("%s", p_ftp_buf);
    _login = false;
  }
  wait_us(2000000);
  memset(p_ftp_buf, 0, strlen(p_ftp_buf));

  // store user info in ftp communication print and send it
  sprintf(p_ftp_buf, "USER %s\r\n", user);
  FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));

  // recieve ftp server message and print if correct
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }
  if (strncmp(p_ftp_buf, "331", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    printf("%s", p_ftp_buf);
    _login = false;
  }
  wait_us(2000000);
  memset(p_ftp_buf, 0, strlen(p_ftp_buf));

  // store password in string and send it to server
  sprintf(p_ftp_buf, "PASS %s\r\n", pass);
  FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
  wait_us(2000000);

  // recieve ftp server info and print it
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("LINE: %d\r\n", __LINE__);
    printf("%s", p_ftp_buf);
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    wait_us(3000000);
    printf("%s", p_ftp_buf);
  }
  if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
    printf("LINE: %d\r\n", __LINE__);
    printf("%s", p_ftp_buf);
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  } else {
    wait_us(3000000);
    printf("%s", p_ftp_buf);
  }

  // check login was successful
  if (strncmp(p_ftp_buf, "230", 3) != 0) {
    printf("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
    return false;
  }

  memset(p_ftp_buf, 0, strlen(p_ftp_buf));
  _login = true;
  return true;
}
220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 4 of 500 allowed.
220-Local time is now 03:25. Server port: 21.
220-This is a private system - No anonymous login
220 You will be disconnected after 15 minutes of inactivity.
331 User user OK. Password required
230-Your bandwidth usage is restricted
230-OK. Current restricted directory is /
230 1941 Kbytes used (0%) - authorized: 2048000 Kb
FTP Connection successful