Pregunta

Estoy trabajando en un servidor HTTP en c ++, y ahora funciona para solicitudes de archivos de texto, pero al intentar obtener un jpeg o algo así, solo se envía parte del archivo. El problema parece ser que cuando uso fgets (buffer, 2000, return_file) parece que el indicador de posición del archivo incrementa mucho más de lo que realmente termina poniendo en el búfer. ¿Por qué sucedería esto? Pongo todo mi código a continuación. El problema se produce en el bucle while (verdadero) que se produce cuando el código de respuesta es 200. Gracias a todos los que respondieron.

// 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;
¿Fue útil?

Solución

No use fgets () para leer datos binarios que necesitan sobrevivir bit a bit. No desea la traducción del separador de registros, y algunos sistemas pueden asumir que es texto si lo lee de esa manera. En este sentido, las nuevas líneas y los separadores de registros no tienen ningún significado, por lo que la función fgets () `de escanearlos es, en el mejor de los casos, una ineficiencia confusa y, en el peor, simplemente no tiene capacidad binaria.

Use fread (3) , o mejor aún, use la llamada al sistema sin formato (Posix API de todos modos, en no-Unix), lea (2). Esto leerá una cierta cantidad de datos bit a bit y le dirá cuánto leen. (Con respecto a que se usa la API con capacidad binaria: normalmente, se nos aconseja almacenar datos en búfer porque generalmente los procesamos en unidades pequeñas como líneas. Sin embargo, al mover un archivo completo de un lugar a otro solo búfer En este caso, es más simple y más rápido utilizar simplemente read () .)

Tampoco puede strlen () datos binarios. Solo tienes que usar el recuento de bytes de la llamada a la API.

Otros consejos

¿No utilizaría strlen break en archivos binarios?

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

Es muy probable que sus archivos binarios contengan bytes NULOS ( '\ 0' ). Cuando lee datos con fgets , puede colocarse en el búfer, pero cuando lo transmite todo después de que \ 0 se pierda (su llamada strlen asegura esto).

Por lo tanto, debe usar fread para leer los datos. Devuelve una cantidad de bytes que realmente se leyeron, por lo que no necesita usar strlen en absoluto. ¡Y no olvides abrir el archivo en modo binario!

Mejor, lea sobre la asignación de archivos a la memoria, de esa manera no tendrá que administrar los búferes para leer el contenido del archivo, y puede pasar ese búfer a enviar y obtendrá el tamaño del archivo de una manera .

Si realmente desea leer bytes del archivo, debe distinguir los archivos binarios de lectura (con el tipo de mimo correcto o application / octet-stream , almacenar el recuento de lecturas de bytes con el búfer) y abrir archivos como texto ( text / * mime-types, y puede usar strlen).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top