这两日在工作中,新接手前人留下的代码,在修改bug过程中, 发现当报文内容很短时,在boost::asio::read_until()之后调用boost::asio::read()未读出预期的数据。部分代码如下:
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
std::istream response_stream(&response);
String http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
String status_message;
std::getline(response_stream, status_message);
if(!response_stream || http_version.substr(0, 5) != "HTTP/"){
return 500;//"Invalid response\n"
}
if(status_code != 200){
return status_code;
}
boost::asio::read_until(socket, response, "\r\n\r\n");
String header, content_len;
int len = 0;
int body_len = 0;
while(std::getline(response_stream, header) && header != "\r"){
//do something ...
if((len = header.find("Content-Length:")) != std::string::npos){
content_len = header.substr(len + 16);//strlen("Content-Length: ")
body_len = atoi(content_len.c_str());
}
}
if(body_len == 0){
body_len = 10240;
}
while(boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), ec)){
std::ostringstream ss2;
ss2<<&response;
httpbody.append(ss2.str());
body_len -= ss2.str().length();
if(body_len <= 0 || ec == boost::asio::error::eof){
break;
}
..................................
}
在第二次read_until
boost::asio::read_until(socket, response, "\r\n\r\n");
后,&response指向了"\r\n\r\n"后的数据,为期望数据开始的地方,但其中的数据大小为512-("\r\n\r\n")这之前的数据。
当进行再次read,
while(boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), ec))
能够读取报文(TCP) data段 512字节以后的内容。response string流还是指向"\r\n\r\n"之后的内容。并且重新为最多512字节数据。(每次循环最多读512字节?)
但如果(TCP)报文数据段小于512字节(HTTP头+数据),那么该段代码在read时就会返回0,读不到数据。while中对数据的处理就未进行。
为了完善功能,先将response中剩余的数据存储起来,判断是否还有数据,再进行read读取。如下:
std::ostringstream ss;
ss<<&response;
httpbody.append(ss.str());
body_len -= ss.str().length();
while((body_len>0)&&boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), ec)){
std::ostringstream ss2;
ss2<<&response;
httpbody.append(ss2.str());
body_len -= ss2.str().length();
if(body_len <= 0 || ec == boost::asio::error::eof){
break;
}
..................................
}
本人没有boost库使用经验,查了些资料,没有看到太多关于asio::read的用法,讲得较多的是asio::read_some()和asio::async_read()。也不知道它们能避免上述问题不,目前问题已解决,不做深入研究了。