C套接字无效的范围标头

问题描述 投票:-1回答:1

我正在尝试制作一个程序,为其他人提供下载文件。它侦听端口并接受任何请求并通过套接字发送文件。我还不担心NAT。

我遇到的问题是用aria2c(或wget)下载该文件会给我“无效的范围标题错误”。但是,本地下载(从127.0.0.1下载)工作正常。

知道它可能会导致问题,我通过添加-x1标志禁用aria2c上的多线程下载。

我究竟做错了什么?


错误是:

12/23 20:04:07 [ERROR] CUID#8 - Download aborted. URI=http://104.38.127.225:8000
Exception: [AbstractCommand.cc:351] errorCode=8 URI=http://104.38.127.225:8000
  -> [HttpResponse.cc:86] errorCode=8 Invalid range header. Request: 98304-187031/187032, Response: 0-187031/187032

关于代码的一些解释:

  1. findFilename只是从文件路径生成文件名
  2. serveFile打开一个套接字并监听它以发送连接到它的任何人指定的文件

我的代码:

#include <stdio.h>
#include <stdlib.h>

#include <netdb.h>
#include <netinet/in.h>

#include <string.h>

#include <unistd.h> /* for close() */

/* find file name from path */
/* file name have to be shorter than 512 characters*/
/* remember to deallocate memory */
char *findFilename(char *filepath)
{
  size_t pt;
  size_t filenamePt = 0;
  char ch;
  char *filename = (char*) malloc(512);

  for (pt = 0; pt < strlen(filepath); pt++)
  {
    ch = filepath[pt];
    filename[filenamePt] = ch;
    filenamePt++;

    if(ch == '/')
    {
      bzero(filename, 512);
      filenamePt = 0;
    }
  }

  filename[filenamePt + 1] = '\0';

  return filename;
}

int serveFile(char* filepath, int port)
{
  FILE *file;
  char *buffer;
  long int fileLength;
  size_t bufferSize;

  /* get file name */
  char* filename = findFilename(filepath);
  if (!filename)
  {
    fprintf(stderr, "file path error\n");
    return -1;
  }



  /* open file */
  file = fopen(filepath, "rb");
  if (!file)
  {
    fprintf(stderr, "file open error\n");
    return -1;
  }

  /* get file length */
  fseek(file, 0, SEEK_END);
  fileLength=ftell(file);
  fseek(file, 0, SEEK_SET);
  bufferSize = fileLength + 1;

  /* allocate memory */
  buffer=(char *)malloc(bufferSize);
  if (!buffer)
  {
      fprintf(stderr, "allocate memory error\n");
      fclose(file);
      return -1;
  }

  /* read file */
  fread(buffer, fileLength, 1, file);
  fclose(file);

  /* compose header */
  char header[1024];

  sprintf(header,
          "HTTP/1.1 200 OK\n"
          "Content-Length: %li\n"
          "Accept-Ranges: bytes\n"
          "Content-Disposition: attachment; filename=\"%s\"\n"
          "\n", fileLength, filename);

  /* do not need filename anymore */
  free(filename);

  /* create socket */
  int socketfd = socket(PF_INET, SOCK_STREAM, 0);

  /* configure socket */
  struct sockaddr_in address;

  bzero(&address, sizeof(address));
  address.sin_family = AF_INET;
  address.sin_port = htons(port); /* host to network short */
  address.sin_addr.s_addr = INADDR_ANY;

  /* bind & listen */
  if(bind(socketfd, (struct sockaddr*) &address, sizeof(address)) != 0)
  {
    fprintf(stderr, "bind error\n");
    return -1;
  }

  if (listen(socketfd, 16)!=0)
  {
    fprintf(stderr, "listen error\n");
    return -1;
  }

  /* accept client */
  while (1)
  {
    socklen_t size = sizeof(address);
    int clientSocket = accept(socketfd, (struct sockaddr*) &address, &size);

    puts("client connected");

    if (fork() == 0)
    {
      write(clientSocket, header, strlen(header));
      write(clientSocket, buffer, bufferSize);
      exit(0);
    }
    else
    {
      close(clientSocket);
    }
  }

}


int main(int argc, char *argv[])
{
  if (argc < 3 || argc > 3)
  {
    fprintf(stderr, "needs 2 arguments: file path & port\n");
    return -1;
  }
  char *filepath = argv[1];
  int port = atoi(argv[2]);

  printf("serving %s on port %d\n"
       "file name(not path) cannot exceed 512 characters\n"
         "keyboard interrupt to kill\n", filepath, port);
  serveFile(filepath, port);
}
c sockets http
1个回答
1
投票
12/23 20:04:07 [ERROR] CUID#8 - Download aborted. URI=http://104.38.127.225:8000
Exception: [AbstractCommand.cc:351] errorCode=8 URI=http://104.38.127.225:8000
   -> [HttpResponse.cc:86] errorCode=8 Invalid range header. Request: 98304-187031/187032, Response: 0-187031/187032

你附加的错误说明了一切,真的。

您的代码假定对服务器发出的每个请求都是一个请求整个文件的请求。

出于很多好的理由,情况并非总是如此(参见编辑)。

Range请求(using the Range header)允许客户端请求文件的一部分,这允许将下载分成块并在网络故障后恢复下载。

但是,无论请求是什么,您的代码也会发送整个文件。

此外,您的代码正在发送Accept-Ranges标头,表示将遵守Range请求(即使不是)。

在这种情况下,客户端抱怨你的代码,表明它请求了一个块,你的代码发送了整个代码。

编辑

正如@RemyLebeau指出的那样,the Range function is optional, though widely used

这就是你有时只收到错误的原因......

aria2c似乎在某种程度上需要范围功能,或者它不能作为下载管理器工作(毕竟管理下载是Range功能的目的)。

其他下载工具不需要(或利用)此功能。

© www.soinside.com 2019 - 2024. All rights reserved.