题
我正在HTTP服务器在c++,而现在它可以作为要求的文本的文件,但是,当试图获得一个jpeg或什么东西,只有部分文件被发送。该问题似乎是,当我使用fgets(缓冲区,2000年,returned_file),这似乎增加的文件的位置指标远远超过它实际上结束了投入缓冲区。为什么会这样?我把我所有的代码如下。问题出现在while(true)循环发生的响应时代码200。谢谢你对任何人的答复。
// 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()
阅读的二进制数据,需要生存的位为位。你不想记录分隔的翻译,一些系统可以假设它的文本如果你读过这种方式。对于这个问题,新行和记录的分离器都完全毫无意义,因此fgets()`功能扫描为他们是最好的一个令人困惑的效率低下和在最坏的情况根本不是-二进制能力。
使用 fread(3)
, 或者更好的是,使用原始系统调(Posix API无论如何,在非Unix)读取(2)条。这将读一定数量的位为位的数据,并告诉你多少阅读。(关于 哪 二进制能够API使用:通常情况下,我们建议缓冲区的数据,因为我们通常过程中,它在小型单位像线路。但是,当整个文件从一个地方到另一个地方的缓冲,只是你的速度慢了下来。在这种情况下,它是更简单和更快的只是使用 read()
.)
你也不能 strlen()
二进制数据。你必须刚好使用本字节的数从API的呼吁。
其他提示
不会在二进制文件上使用strlen break吗?
send( acc_tcp_sock, buffer, strlen(buffer), 0 )
您的二进制文件很可能包含NULL字节('\ 0'
)。当您使用 fgets
读取数据时,它可能被放入缓冲区,但是当您在 \ 0
之后传输它时( strlen
调用)确保这一点。)
因此,您需要使用 fread
来读取数据。它返回实际读取的字节数,因此您根本不需要使用strlen。并且不要忘记以二进制模式打开文件!
更好的是,阅读有关将文件映射到内存的方法,这样您就不必管理用于读取文件内容的缓冲区,并且可以将该缓冲区传递给 send
,并以一种方式获取文件大小
如果你真的想从文件中读取字节,那么你必须区分读取二进制文件(使用正确的mime类型或 application / octet-stream
,用缓冲区存储字节读取计数)和打开文件作为文本( text / *
mime-types,你可以使用strlen)。