C ++의 HTTP 서버가 모든 파일을 올바르게 다시 전송하지 않습니다.
문제
나는 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을 사용할 수 있습니다).