2

我正在使用 c++ 开发 HTTP 服务器,现在它适用于文本文件的请求,但是当尝试获取 jpeg 或其他内容时,只有部分文件被发送。问题似乎是当我使用 fgets(buffer, 2000, returned_file) 时,它似乎增加了文件位置指示器,而不是它实际上最终放入缓冲区。为什么会发生这种情况?我把我所有的代码放在下面。问题出现在响应码为200时发生的while(true)循环中。感谢任何回复的人。

// 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;
4

4 回答 4

6

不要fgets()用于读取需要逐位生存的二进制数据。您不需要记录分隔符翻译,如果您以这种方式阅读,某些系统可能会认为它是文本。就此而言,换行符和记录分隔符完全没有意义,因此扫描它们的 fgets() 函数充其量是一种令人困惑的低效率,最坏的情况是根本不具备二进制功能。

使用fread(3),或者更好的是,使用原始系统调用(Posix API 无论如何,在非 Unix 上)read(2)。这将读取一定数量的逐位数据并告诉您它读取了多少。(关于使用哪个支持二进制的 API:通常,建议我们缓冲数据,因为我们通常以行等小单位处理数据。但是,当将整个文件从一个地方移动到另一个地方时,缓冲只会减慢您的速度。在这种情况下使用起来更简单、更快捷read()。)

你也不能strlen()二进制数据。您只需使用 API 调用中的字节数。

于 2009-11-27T19:16:15.690 回答
5

不会在二进制文件上使用 strlen break 吗?

send( acc_tcp_sock, buffer, strlen(buffer), 0 )
于 2009-11-27T19:15:35.783 回答
3

It is very probable that your binary files contain NULL bytes ('\0'). When you read data with fgets, it may be placed into buffer, but when you transmit it everything after \0 gets lost (your strlen call ensures this).

So, you need to use fread to read data. It returns a number of bytes that were actually read, so you don't need to use strlen at all. And don't forget to open file in binary mode!

于 2009-11-27T19:17:35.013 回答
0

Better, read about mapping files to memory, that way you don't have to manage buffers for reading file content, and you can pass that buffer to send and you get file size in one way.

If you really want to read bytes from file, then you have to distinguish reading binary files (with correct mime type or application/octet-stream, storing bytes read count with buffer) and opening files as text (text/* mime-types, and you can use strlen).

于 2009-11-27T19:47:33.390 回答