Meu servidor http no c ++ não está enviando todos os arquivos de volta corretamente

StackOverflow https://stackoverflow.com/questions/1810277

  •  05-07-2019
  •  | 
  •  

Pergunta

Eu estou trabalhando em um servidor HTTP em C ++, e agora ele funciona para solicitações de arquivos de texto, mas ao tentar obter um jpeg ou algo assim, apenas uma parte do arquivo é enviado. O problema parece ser que quando eu usar fgets (tampão de 2000, returned_file) parece incrementar o indicador de posição do arquivo muito mais do que realmente acaba colocando no buffer. Por que isso aconteceu? Eu coloquei todo o meu código abaixo. O problema ocorre em while (true) loop que ocorre quando o código de resposta é 200. Obrigado a quem responde.

// Interpret the command line arguments
unsigned short port = 8080;

if ( (argc != 1) && (argc != 3) && (argc != 5) ) {
  cerr << "Usage: " << argv[0];
  cerr << " -p <port number> -d <base directory>" << endl;
  return 1;
}
else {
  for (int i = 1; i < argc; ++i) {
    if (strcmp(argv[i], "-p") == 0)
      port = (unsigned short) atoi(argv[++i]);
    else if (strcmp(argv[i], "-d") == 0)
      base_directory = argv[++i];
  }
}
// if base_directory was not given, set it to current working directory
if ( !base_directory ) {
  base_directory = getcwd(base_directory, 100);
}

// Create TCP socket
int tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_sock < 0) {
  cerr << "Unable to create TCP socket." << endl;
  return 2;
}

// Create server socket
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons( port );
server.sin_addr.s_addr = INADDR_ANY;

// Bind the socket
if (bind(tcp_sock, (sockaddr*)&server, sizeof(server)) < 0) {
  cerr << "Unable to bind TCP socket." << endl;
  return 3;
}

// Listen for a connection request on TCP port
listen(tcp_sock, 5);

// Create HTTP_Request object and start a while loop of accepting connections
char buffer[2000];
int bytes_recv = 0;
int recv_len = 0;
string error_reply;

HTTP_Response* response;

while (true) {
  int acc_tcp_sock = accept(tcp_sock, NULL, NULL);
  if (acc_tcp_sock == -1) {
    cerr << "Unable to open TCP connection with client." << endl;
  }
  do {
    // may want to do just one recv
    recv_len = recv( acc_tcp_sock, buffer + bytes_recv,
      2000 - bytes_recv, 0 );
    bytes_recv += recv_len;
  } while (false);
  bytes_recv = 0;
  // may want to see if this causes a memory leak
  HTTP_Request* request = HTTP_Request::Parse(buffer, 2000);

  response = handle_request(request); // function to handle the request

  // Put response header into buffer
  response->Print( buffer, 2000 );

  // if 200 and GET then send header with file
  if ( response->Get_code() == 200 ) {
    // send response header
    if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
      cerr << "Unable to send response header to client." << endl;
    }
    if ( method == "GET" ) {
      // send file
      while ( true ) {
        fgets( buffer, 2000, returned_file );
        if ( feof( returned_file ) ) break;
        if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
          cerr << "Unable to send file in response to client." << endl;
        }
      }
    }
    fclose( returned_file ); // close file
  }
  else {
    if ( method == "GET" ) {
      error_reply = buffer + error_page;
      if ( send( acc_tcp_sock, error_reply.c_str(), error_reply.length(), 0 ) < 0 ) {
        cerr << "Unable to send response to client." << endl;
      }
    }
    else {
      if ( send( acc_tcp_sock, buffer, strlen(buffer), 0 ) < 0 ) {
        cerr << "Unable to send respone header to client." << endl;
      }
    }
  }

  close( acc_tcp_sock ); // close the connection
}

return 0;
Foi útil?

Solução

Não use fgets() para ler os dados binários que necessita para sobreviver bit-por-bit. Você não quer tradução recorde de separador, e alguns sistemas podem assumir que é texto se você lê-lo dessa forma. Para essa matéria, novas linhas e gravar separadores são completamente sem sentido para que os fgets () função `de digitalização para eles é na melhor das hipóteses uma ineficiência confuso e, na pior, simplesmente não-binary-capaz em tudo.

Use fread(3), ou melhor ainda, utilizar a chamada matéria sistema (POSIX API de qualquer maneira, sobre a não-Unix) read (2). Isto irá ler uma certa quantidade de dados bit-por-bit e dizer-lhe o quanto ele ler. (Em relação a que API binário capaz de usar: normalmente, somos aconselhados a buffer de dados, porque nós normalmente processá-lo em pequenas unidades, como linhas No entanto, ao mover um arquivo inteiro de um lugar para outro buffer apenas. retarda para baixo. neste caso é mais simples e mais rápido para read() uso apenas.)

Você também pode não strlen() dados binários. Você só tem que usar a contagem de bytes da chamada API.

Outras dicas

Será que não usar pausa strlen em arquivos binários?

send( acc_tcp_sock, buffer, strlen(buffer), 0 )

É muito provável que seus arquivos binários conter bytes nulos ('\0'). Quando você lê dados com fgets, pode ser colocado em buffer, mas quando você transmiti-lo tudo depois \0 se perde (sua chamada strlen garante isso).

Então, você precisa usar fread para ler os dados. Ele retorna um número de bytes que foram realmente ler, assim você não precisa usar strlen em tudo. E não se esqueça de abrir o arquivo em modo binário!

Melhor, ler sobre arquivos de mapeamento para a memória, de que maneira você não tem que gerenciar buffers para ler o conteúdo do arquivo, e você pode passar esse buffer para send e você obter o tamanho do arquivo de uma maneira.

Se você realmente quer ler bytes de arquivo, então você tem que distinguir leitura de arquivos binários (com o tipo mime correto ou application/octet-stream, armazenamento de bytes ler contagem com tampão) e abrir arquivos como texto (text/* mime-types, e você pode usar strlen).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top