为了实现一个收到HTTPS响应的接口,我的实现思路是这样的:
分三步对响应进行接收,第一步先接收response_line, 第二步接收response_header , 最后一步对reponse_body进行接收。
在代码上,因为前两步都有明显的结束标识符,response line使用"\r\n"作为结束标识库,response header使用"\r\n\r\n"作为结束标识库,这些都是HTTP标准规定的,所以不会有问题,而response body使用一个计时器,当接收超时100ms后,表示当前body已经接收完成。
代码逻辑如下:
读取response line:
asio
::
async_read_until
(
socket_
,
response_
,
MatchResponseLine
,
bind
(&
HttpsWebClient
::
OnReadResponseLineHandler
,
this
,
web_response
,
response_handler
,
asio
::
placeholders
::
error
,
asio
::
placeholders
::
bytes_transferred
)
);
MatchResponseLine中对"\r\n"进行遍历,找到就返回相应的response_迭代器位置,然后读取完成后调用回调函数OnReadResopnseLineHandler
读取reponse header:
asio
::
async_read_until
(
socket_
,
response_
,
MatchResponseHeader
,
bind
(&
HttpsWebClient
::
OnReadResponseHeaderHandler
,
this
,
web_response
,
response_handler
,
asio
::
placeholders
::
error
,
asio
::
placeholders
::
bytes_transferred
)
);
解析如上。
读取response body:
socket_.async_read_some(
asio::buffer(read_data_buffer_, READ_DATA_BUFFER_SIZE),
bind(&HttpsWebClient::OnReadResponseBodyHandler, this,
web_response,
response_handler,
asio::placeholders::error,
asio::placeholders::bytes_transferred)
这三次调用是顺序调用的,也就是在OnReadResponseLineHandler中调用了read response header, 然后在OnReadResonseHeaderHandler中调用了read reponse body.
然后就出现了问题,当读取reponse line和reponse body时就能够正常的拿到所有数据。但最后一步读取reponse body的时候就发现body的前120个字节不见了。
一开始以为是boost 的 asyn_read_some接口出问题了,上google查了下发现没有人有遇到类似的问题,但还是换了下接口,换成asyn_read,改了下相关的逻辑,发现没有办法解决问题。于是就开始怀疑是缓冲区的处理的问题,
使用单步调试进入MatchResponseHeader中,发现在read response header的时候就已经把body的一部分数据读到了response_缓冲区中了,而当我们去读body的时候,使用了另外一个缓冲区read_data_buffer_缓冲区,导致了body开头的数据丢失。
所以发现问题后,解决方法就是在read response body中也使用相同的response_缓冲区。
修改后的代码如下:
asio
::
async_read
(
socket_
,
response_
,
//asio::buffer(read_data_buffer_, READ_DATA_BUFFER_SIZE),
boost
::
asio
::
transfer_at_least
(
1
),
bind
(&
HttpsWebClient
::
OnReadResponseBodyHandler
,
this
,
web_response
,
response_handler
,
asio
::
placeholders
::
error
,
asio
::
placeholders
::
bytes_transferred
)
);
验证后证明是OK的。