【问题标题】:ftp client reads incomplete messages from serverftp 客户端从服务器读取不完整的消息
【发布时间】:2014-03-18 19:55:56
【问题描述】:

这是我的代码简单的 ftp 客户端,我可以连接到服务器登录,但我的程序从服务器读取随机不完整的消息,有时它们是完整的,但有时它只读取几个字节,我不知道该怎么做请帮助我

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>

#define BUF_SIZE 5000

int main()
{
  struct addrinfo hints;
  struct addrinfo *result, *rp;
  int my_socket, passive_socket, sock, len, m = 0, bytes;
  char buf[BUF_SIZE], i[BUF_SIZE];

  memset(&hints, 0, sizeof(struct addrinfo));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = 0;

  if ((sock = getaddrinfo("ftp.linux.cz", "ftp", &hints, &result)) != 0)
  {
    fprintf(stderr, "%s\n", gai_strerror(sock));
    exit(EXIT_FAILURE);
  }

  for (rp = result; rp != NULL ; rp = rp->ai_next)
  {
    if ((my_socket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))
        == -1)
      continue;
    if (connect(my_socket, rp->ai_addr, rp->ai_addrlen) != -1)
      break;
    close(my_socket);
  }

  freeaddrinfo(result);

  read(my_socket, buf, BUF_SIZE);
  printf("%s", buf);

  len = strlen("USER anonymous\r\n");
  write(my_socket, "USER anonymous\r\n", len);

  read(my_socket, buf, BUF_SIZE);
  printf("%s", buf);

  len = strlen("PASS secret\r\n");
  write(my_socket, "PASS secret\r\n", len);

  read(my_socket, buf, BUF_SIZE);
  printf("%d\n", bytes);
  for (int n = 0; n < bytes; n++)
    printf("%c", buf[n]);

  len = strlen("EPSV\r\n");
  write(my_socket, "EPSV\r\n", len);

  read(my_socket, buf, BUF_SIZE);
  //printf( "%s", buf );  

  for (int n = 39; n > 0; n++)
  {
    if (buf[n] >= 48 && buf[n] <= 57)
    {
      i[m] = buf[n];
      m++;
    }
    else
    {
      i[m] = '\0';
      n = -1;
    }
  }

  printf("%s\n", i);

#if 0
  if ((sock = getaddrinfo("ftp.fit.vutbr.cz", i, &hints, &result)) != 0)
  {
    fprintf(stderr, "%s\n", gai_strerror(sock));
    exit(EXIT_FAILURE);
  }

  for (rp = result; rp != NULL ; rp = rp->ai_next)
  {
    if ((passive_socket = socket(rp->ai_family, rp->ai_socktype,
        rp->ai_protocol)) == -1)
      continue;
    if (connect(passive_socket, rp->ai_addr, rp->ai_addrlen) != -1)
      break;
    close(passive_socket);
  }

  read(passive_socket, buf, BUF_SIZE);
  printf("%s", buf);

  len = strlen("NLST\r\n");
  write(my_socket, "NLST\r\n", len);

  read(passive_socket, buf, BUF_SIZE);
  printf("%s", buf);
#endif

  return 0;
}

【问题讨论】:

  • 也许可以尝试bzero(buf,BUF_SIZE); 以确保您的缓冲区每次都是干净的
  • Closely read read()/write() 和 learn 的手册页b> 这两个函数不一定接收/发送 bytes 和它们被告知一样多,但很少。因此,围绕此类调用进行循环计数,直到所有预期数据或已接收/发送终止符是一个好主意,而不是说基本必要
  • 我试图清除缓冲区,但仍然相同,例如,对于这个循环,我们有 5 行的消息,一个循环读取第一个循环,然后我们转到另一个循环,服务器如何知道他必须向我们发送第二个行吗?

标签: c sockets ftp


【解决方案1】:

您不能假设 read 一次读取整个响应,它可以读取更少,它可以读取 BUF_SIZE 字节,但在一次调用期间不能读取更多。

您的程序显然缺少一个干净的解析器。您应该对您正在阅读的内容做出适当的反应,这可能是信息性消息、警告、错误或其他任何内容。

如果你想为FTP 协议滚动你自己的解析器,我能给你的最好建议是查看State Machine Pattern,然后查看Lexical Analyzerproperly built parsers 以便执行所以。

通过这种方式,您最终将能够构建功能强大且健壮的网络应用程序。

【讨论】:

  • 但是我怎么知道我已经阅读了整个消息是服务器发送 EOF?
  • IIRC,服务器不关闭连接。如果我没记错,它会在每条消息的末尾发送\n\r\n
  • 所以我需要循环直到我找到 \n 对吗?是不是 linux 的 \n 和 windows 的 \r\n ?
  • 我不知道,这取决于这种情况下的协议状态(如果作为命令的一部分的消息中间有 \n 会发生什么?)。正如我在回答中所说,您基本上需要深入研究 RFC 959 并相应地实现您的解析器所在的states,以及在每次接收字符时它转换的状态。
  • 我在我的计算机上对 FTP 会话进行了快速的 Wireshark 捕获,在我的例子中,每个命令都附加了 \r\n。出于教育目的,您也应该这样做,如果您怀疑某个特定功能或行为,这个工具可能是您更好的朋友。
猜你喜欢
  • 2016-03-18
  • 2015-10-08
  • 1970-01-01
  • 2017-04-30
  • 2013-03-02
  • 1970-01-01
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
相关资源
最近更新 更多