C ++의 HTTP 서버가 모든 파일을 올바르게 다시 전송하지 않습니다.

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

  •  05-07-2019
  •  | 
  •  

문제

나는 C ++의 HTTP 서버에서 작업하고 있으며 지금은 텍스트 파일의 요청에 대해 작동하지만 JPEG 또는 무언가를 얻으려고 할 때 파일의 일부만 전송됩니다. 문제는 fgets (Buffer, 2000, returned_file)를 사용할 때 실제로 버퍼에 넣는 것보다 파일 위치 표시기를 훨씬 더 증가시키는 것 같습니다. 왜 이런 일이 일어날까요? 내 코드를 모두 아래에 넣었습니다. 문제는 응답 코드가 200 일 때 발생하는 (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;
도움이 되었습니까?

해결책

사용하지 마십시오 fgets() 비트 비트에서 살아남는 데 필요한 이진 데이터를 읽습니다. 레코드 분리기 번역을 원하지 않으며 일부 시스템은 그런 식으로 읽으면 텍스트라고 가정 할 수 있습니다. 그 문제에 대해, Newlines와 Record-Separators는 완전히 의미가 없으므로 fgets ()`그들을 스캔하는 기능은 가장 혼란스러운 비 효율성이며 최악의 경우 이진을 전혀 사용할 수 없습니다.

사용 fread(3), 또는 더 나은 방법으로, 원시 시스템 호출 (어쨌든 posix api, nonix) 읽기 (2)를 사용하십시오. 이것은 일정량의 비 비트 비트 데이터를 읽고 읽은 양을 알려줍니다. (에 관하여 어느 사용할 바이너리 캡처 API 사용 : 일반적으로 데이터를 완충하는 것이 좋습니다. 그러나 전체 파일을 한 장소에서 다른 버퍼링으로 이동하면 속도가 느려집니다. 이 경우 사용하는 것이 더 간단하고 빠릅니다. read().)

당신도 할 수 없습니다 strlen() 이진 데이터. API 호출에서 바이트 수를 사용해야합니다.

다른 팁

이진 파일에서 strlen 브레이크를 사용하지 않습니까?

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

이진 파일에 null 바이트가 포함되어있을 가능성이 매우 높습니다.'\0'). 데이터를 읽을 때 fgets, 그것은 버퍼에 배치 될 수 있지만 이후에 모든 것을 전송할 때 \0 길을 잃습니다 (당신의 strlen 호출은 이것을 보장합니다).

따라서 사용해야합니다 fread 데이터를 읽으려면. 실제로 읽은 여러 바이트를 반환하므로 Strlen을 전혀 사용할 필요가 없습니다. 이진 모드에서 파일을 열는 것을 잊지 마십시오!

더 나은 것은 파일을 메모리에 매핑하는 것에 대해 읽고, 파일 컨텐츠를 읽기 위해 버퍼를 관리 할 필요가 없으며 해당 버퍼를 전달할 수 있습니다. send 그리고 당신은 한 가지 방식으로 파일 크기를 얻습니다.

파일에서 바이트를 읽고 싶다면 이진 파일을 읽는 것을 구별해야합니다 (올바른 Mime 유형 또는 application/octet-stream, 바이트 저장 버퍼와 함께 읽기 카운트) 및 텍스트로 파일을 열면 (text/* 마임 유형은 strlen을 사용할 수 있습니다).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top