Boost::asio範例分析 客戶端

  爲了方便描述,這裏只分析一下同步實現,異步實現方式和同步方式的流程是一致的,只是在函數調用的方式上有些區別.分析清楚了同步方式,在看異步實現,也很容易.

  這個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);

 

發佈了705 篇原創文章 · 獲贊 50 · 訪問量 206萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章