Question

Je travaille sur un serveur HTTP en c ++ et, pour le moment, cela fonctionne pour les demandes de fichiers texte, mais lorsque vous essayez d’obtenir un fichier jpeg ou quelque chose du genre, seule une partie du fichier est envoyée. Le problème semble être que, lorsque j'utilise fgets (buffer, 2000, return_file), il semble que l'indicateur de position du fichier incrémente beaucoup plus que ce qu'il finit par mettre dans le tampon. Pourquoi cela arriverait-il? Je mets tout mon code ci-dessous. Le problème se produit dans la boucle while (true) qui se produit lorsque le code de réponse est 200. Merci à tous ceux qui répondent.

// 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;
Était-ce utile?

La solution

N'utilisez pas fgets () pour lire les données binaires devant survivre bit à bit. Vous ne voulez pas de traduction séparateur d'enregistrement, et certains systèmes peuvent supposer que c'est du texte si vous le lisez de cette façon. À cet égard, les nouvelles lignes et les séparateurs d’enregistrements n’ont aucune signification, la fonction d’analyse de fgets () `est au mieux une inefficacité déroutante et, au pire, tout simplement pas du tout.

Utilisez fread (3) ou, mieux encore, utilisez l'appel système brut (API Posix de toute façon, sur les lecteurs non Unix) read (2). Cela lira une certaine quantité de données bit à bit et vous indiquera combien de fois elles ont été lues. (En ce qui concerne l’API compatible binaire à utiliser: normalement, il est conseillé de mettre les données en mémoire tampon, car nous les traitons généralement par petites unités, comme des lignes. Toutefois, lors du déplacement d’un fichier entier d’un endroit à un autre Dans ce cas, il est plus simple et plus rapide d’utiliser simplement read () .)

Vous ne pouvez pas non plus strlen () données binaires. Vous devez simplement utiliser le nombre d'octets de l'appel API.

Autres conseils

N'utilisez-vous pas strlen sur les fichiers binaires?

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

Il est très probable que vos fichiers binaires contiennent des octets NULL ( '\ 0' ). Lorsque vous lisez des données avec fgets , elles peuvent être placées dans la mémoire tampon, mais lorsque vous transmettez tout, après la perte de \ 0 (votre appel strlen assure cela).

Donc, vous devez utiliser fread pour lire les données. Il renvoie un nombre d'octets qui ont été réellement lus, vous n'avez donc pas besoin d'utiliser strlen du tout. Et n'oubliez pas d'ouvrir le fichier en mode binaire!

Mieux, lisez à propos du mappage des fichiers sur la mémoire. Ainsi, vous n'avez pas à gérer les tampons pour lire le contenu des fichiers. Vous pouvez transmettre ce tampon à envoyer et obtenir une taille de fichier unique. .

Si vous voulez vraiment lire les octets d'un fichier, vous devez distinguer les fichiers binaires de lecture (avec le type mime correct ou application / octet-stream , stocker le nombre d'octets lus avec le tampon) et ouvrir les fichiers. en tant que texte ( text / * mime-types, et vous pouvez utiliser strlen).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top