爲了方便描述,這裏只分析一下同步實現,異步實現方式和同步方式的流程是一致的,只是在函數調用的方式上有些區別.分析清楚了同步方式,在看異步實現,也很容易.
這個HTTP範例實現了客戶端向服務端請求文件內容的功能,客戶端給出一個文件名稱,服務端在本地尋找文件,並將文件內容(文本文件)返回給客戶端.
main函數首先檢查傳遞給exe執行文件的參數,第一個參數是服務端的IP地址,第二個參數是請求的文件名稱,如果僅指定了目錄而沒有具體的文件名,則在這個目錄中查找index.htm文件.
//定義io_service對象實例,任何使用asio的程序中都要進行定義,是asio庫的核心實現.
boost::asio::io_service io_service;
//argv[1]是服務端IP地址,由程序調用方提供,
//在指定服務器上尋找http服務,並獲取網絡端點
tcp::resolver resolver(io_service);
tcp::resolver::query query(argv[1], "http");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
// 嘗試獲取到的每個端點,直到建立了一個有效的鏈接.
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
至此,鏈接建立成功.接下來就是向服務端發送和接受數據了.
//建立一個流緩衝區,用來存儲發送和接受的數據
boost::asio::streambuf request;
//將流緩衝區與一個輸出流ostream綁定,對ostream的輸出操作最終都存入到流緩衝區.
std::ostream request_stream(&request);
//根據客戶端與服務端制定的協議,組織HTTP請求包的頭信息.argv[2]指定了文件名稱.
request_stream << "GET " << argv[2] << " HTTP/1.0\r\n";
request_stream << "Host: " << argv[1] << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
//向服務端發送HTTP請求
boost::asio::write(socket, request);
這時HTTP服務端接受到客戶端發送的請求後,按雙邊協議對請求信息進行解析,獲取到文件名稱和HTTP協議的版本號,並進行相應的處理,將HTTP響應狀態信息,包頭信息和文件內容發送給客戶端.客戶端接收這些信息,並進行檢查處理.
接收響應的狀態信息:
//定義接收響應數據的流緩衝區
boost::asio::streambuf response;
//從服務端接收響應包的頭信息,描述響應的狀態
//流緩衝區可根據接收的數據自動調節大小,可在其構造函數中指定最大流緩衝區.
boost::asio::read_until(socket, response, "\r\n");
檢查響應包的狀態:
//將流緩衝區與istream相關聯,可方便的從流緩衝區中提取出信息
std::istream response_stream(&response);
std::string http_version;
//獲取http版本號
response_stream >> http_version;
unsigned int status_code;
//獲取響應信息的狀態碼
response_stream >> status_code;
std::string status_message;
//獲取狀態信息
std::getline(response_stream, status_message);
//檢查包是否爲HTTP請求的響應包
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
std::cout << "Invalid response\n";
return 1;
}
if (status_code != 200)//狀態碼爲200表示請求成功,否則失敗
{
std::cout << "Response returned with status code " << status_code << "\n";
return 1;
}
如果檢查通過,則開始接收響應包的包頭.
boost::asio::read_until(socket, response, "\r\n\r\n");
//處理響應包頭信息
std::string header;
while (std::getline(response_stream, header) && header != "\r")
std::cout << header << "\n";
std::cout << "\n";
// 打印出所有輸出的信息
if (response.size() > 0) std::cout << &response;
現在開始接收文件內容,直到遇到了EOF符號,並將接收到的數據直接輸出
boost::system::error_code error;
//read函數返回接收到的字節數,這裏用了while循環,表示一直接收,直到接收不到爲止.
// transfer_at_least 函數返回transfer_at_least_t類型,
//這是一個函數對象,會將接收到的數據字節數與其參數相比較,
//如果大於等於指定數量則返回,這裏指定爲1表示接收到數據就返回處理.
while (boost::asio::read(socket, response,
boost::asio::transfer_at_least(1), error))
std::cout << &response;//直接將接收到的數據進行顯示
if (error != boost::asio::error::eof)
throw boost::system::system_error(error);