c - 初学者 ftp 服务器困境,部分 deux

标签 c sockets ubuntu server rtp

当我尝试使用 ftp 访问 ls 命令时,我总是在 PORT 部分中点击 425,有人能告诉我这是为什么吗?我的用户部分工作正常,如果我能让端口工作,我就可以专注于 STOR 和 RETR。

/*FTP server*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h> 
/*for getting file size using stat()*/
#include<sys/stat.h>

/*for sendfile()*/
#include<sys/sendfile.h>

/*for O_RDONLY*/
#include<fcntl.h>
int active=0; 
int sock1, sock2;
char buf[100], command[5], filename[20];
struct sockaddr_in remoteaddr, remoteaddr_data;
int main(int argc,char *argv[])
{
  struct sockaddr_in server, client;
  struct stat obj;
  struct sockaddr_in local_data_addr_act;
  int s, s_data, s_data_act;
  s = socket(AF_INET, SOCK_STREAM, 0);
  s_data = socket(AF_INET, SOCK_STREAM, 0);
  s_data_act = socket(AF_INET, SOCK_STREAM, 0);
  int k, i, size, len, c;
  int filehandle;
  sock1 = socket(AF_INET, SOCK_STREAM, 0);
  if(sock1 == -1)
  {
    printf("Socket creation failed");
    exit(1);
  }
  server.sin_port = htons(atoi(argv[1]));
  server.sin_addr.s_addr = 0;
  k = bind(sock1,(struct sockaddr*)&server,sizeof(server));
  if(k == -1)
  {
    printf("Binding error");
    exit(1);
  }
  k = listen(sock1,1);
  if(k == -1)
  {
    printf("Listen failed");
    exit(1);
  }
  len = sizeof(client);
  sock2 = accept(sock1,(struct sockaddr*)&client, &len);
  write(sock2,"220\r\n", 6);
  i = 1;
  while(1)
  {
    recv(sock2, buf, 100, 0);
    printf("%s\n", buf);
    sscanf(buf, "%s", command);
    printf("%s\n", command);
    if(!strcmp(command, "LIST"))
    {
      system("ls >tmp.txt");
      FILE *fin=fopen("tmp.txt","r");
      sprintf(buf, "125\r\n");
      send(sock2, buf, strlen(buf), 0);
      char temp_buf[10];
      while (!feof(fin))
      {
        fgets(temp_buf, 98, fin);
        sprintf(buf, "%s", temp_buf);
        if (!active)send(sock1, buf, strlen(buf), 0);
        else send(s_data_act, buf, strlen(buf), 0); 
      }
      fclose(fin);
      sprintf(buf, "250\r\n");
      send(sock2, buf, strlen(buf), 0);
      if(!active) close(sock1);
      else close(s_data_act);
      sprintf(buf, "226\r\n");
      send(sock2, buf, strlen(buf), 0);
    }
    else if(!strcmp(command,"USER"))
    {
      sprintf(buf, "230\r\n");
      send(sock2, buf, strlen(buf), 0);
    }
    else if(!strcmp(command,"SYST"))
    {
      write(sock2, "502\r\n", 6);
    }
    else if(!strcmp(command,"PORT"))
    {
      unsigned char act_port[2];
      int act_ip[4], port_dec;
      char ip_decimal[40];
      active=1;
      sscanf(command, "PORT %d,%d,%d,%d,%d,%d",&act_ip[0],&act_ip[1],&act_ip[2],&act_ip[3], &act_port[0], &act_port[1]);
      local_data_addr_act.sin_family=AF_INET;
      sprintf(ip_decimal, "%d.%d.%d.%d", act_ip[0], act_ip[1], act_ip[2], act_ip[3]);
      local_data_addr_act.sin_addr.s_addr=inet_addr(ip_decimal);
      port_dec=act_port[0];
      port_dec=port_dec<<8;
      port_dec=port_dec+act_port[1];
      local_data_addr_act.sin_port=htons(port_dec);
      if (connect(s_data_act,(struct sockaddr*)&local_data_addr_act, (int)sizeof(struct sockaddr))!=0)
      {
        printf("%s%d\n",inet_ntoa(local_data_addr_act.sin_addr),ntohs(local_data_addr_act.sin_port)); 
        sprintf(buf, "425\r\n");
        send(sock2, buf, strlen(buf), 0);
        close(s_data_act);
      }
      else
      {
        sprintf(buf, "200\r\n");
        send(sock2, buf, strlen(buf), 0); 
      }
    }
    else if(!strcmp(command,"RETR"))
    {
      sscanf(buf, "%s%s", filename, filename);
      stat(filename, &obj);
      filehandle = open(filename, O_RDONLY);
      size = obj.st_size;
      if(filehandle == -1)
        size = 0;
      send(sock2, &size, sizeof(int), 0);
      if(size)
        sendfile(sock2, filehandle, NULL, size);
    }
    else if(!strcmp(command, "STOR"))
    {
      int c = 0, len;
      char *f;
      sscanf(buf+strlen(command), "%s", filename);
      recv(sock2, &size, sizeof(int), 0);
      i = 1;
      while(1)
      {
        filehandle = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666);
        if(filehandle == -1)
        {
          sprintf(filename + strlen(filename), "%d", i);
        }
        else
          break;
      }
      f = malloc(size);
      recv(sock2, f, size, 0);
      c = write(filehandle, f, size);
      close(filehandle);
      send(sock2, &c, sizeof(int), 0);
    }
    else if(!strcmp(command, "pwd"))
    {
      system("pwd>temp.txt");
      i = 0;
      FILE*f = fopen("temp.txt","r");
      while(!feof(f))
        buf[i++] = fgetc(f);
      buf[i-1] = '\0';
      fclose(f);
      send(sock2, buf, 100, 0);
    }
    else if(!strcmp(command, "cd"))
    {
      if(chdir(buf+3) == 0)
        c = 1;
      else
        c = 0;
      send(sock2, &c, sizeof(int), 0);
    }
    else if(!strcmp(command, "bye") || !strcmp(command, "QUIT"))
    {
      printf("FTP server quitting..\n");
      i = 1;
      send(sock2, &i, sizeof(int), 0);
      exit(0);
    }
  }
  return 0;
}

最佳答案

这段代码充满了错误和错误。无论您尝试使用此代码实现什么,它都与符合要求的 FTP 服务器实现相差甚远。

您创建了太多套接字,甚至没有使用所有套接字。而且您在错误的时间、错误的条件下创建了其中一些。

大多数套接字/文件函数调用完全缺乏错误处理。

没有正确处理套接字读/写,特别是没有考虑到 TCP 是一种流传输,不提供任何写入和读取之间一对一关系的保证。您必须必须考虑到这一点!

有时向客户端写入不正确的数据 - 发送不期望的空终止符,发送数据缓冲区,就像它们实际上不是空终止一样,在不期望时将文件大小作为二进制整数发送,等等。

假设接收到的数据以 null 终止,但事实并非如此。

将被动模式数据发送到错误的套接字(甚至没有执行 PASV 命令)。

没有正确执行PORTSTORRETR命令(对套接字管理不当)。

未正确执行 PWDCDBYE/QUIT 命令(发送完全无效的回复) .

而且,虽然从技术上来说不是错误,但您确实不应该使用 system()。有更好的本地方法来获取所需的数据。对于LIST,您可以使用opendir()代替,然后根据需要写入目录的条目。对于PWD,您可以使用getcwd()

您需要废弃此代码并重新开始。它有太多问题需要尝试修复。网上有很多关于如何正确实现套接字 I/O 的示例,尤其是如何使用套接字进行基于行的 I/O(因为 FTP 是基于行的协议(protocol))。请阅读RFC 959了解处理 FTP 命令/响应和数据传输管理的正确规则

关于c - 初学者 ftp 服务器困境,部分 deux,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29908687/

相关文章:

python - 指定与 sudo apt-get 一起使用的 python 实例

c - 函数内部的指针变量指向栈还是堆?

c - 使用 XtPointer 传递 int 是否安全?

c++ - 客户端服务器 API 交互

c# - 来自 Xamarin 应用程序的第二次 api 调用失败(第一次调用总是返回正常)

java - Ubuntu 在设置路径后获取模块 java.se.ee

c - 需要将我的固件镜像迁移到 ROM 掩码

c++ - 使用 memcmp、memcpy 优化子例程

c - memcpy() 修改客户端套接字文件描述符

python - 如何将 ubuntu 降级到 python 3.6?