Boost.Asio是一個用于網絡和異步編程的C++庫。它提供了一種跨平臺的方式來處理網絡編程和異步操作,使開發人員能夠創建高性能的網絡應用程序,asio幾乎支持所有你能夠想到的網絡協議,比如tcp、udp、ip、http、icmp等,C++通過asio庫可以輕松實現tcp和http服務器。(本博客默認你已經安裝好了boost庫,并且博主的boost庫版本是1.84.0,集成環境是VS2022)。
第一步配置boost庫的開發環境,相比于其他庫,VS2022配置boost庫的開發環境比較簡單,只需要包含頭文件和靜態鏈接庫就可以了。
首先創建兩個C++控制臺項目,BoostClient和BoostServer。
打開BoostClient的屬性,包含boost的頭文件目錄和靜態鏈接庫目錄就可以了。
首先是服務器端的代碼。
#include <iostream>
#include<boost/asio.hpp>
#include<string>
int main()
{int port = 3333;std::string saddr = "127.0.0.1";boost::asio::ip::address addr = boost::asio::ip::address::from_string(saddr);boost::asio::io_context ioc;boost::asio::ip::tcp::endpoint ep(addr, port);boost::asio::ip::tcp::acceptor ac(ioc, ep);while (true){boost::asio::ip::tcp::socket soc(ioc);//創建套接字必須使用上下文ac.accept(soc);char request[100] = "";soc.receive(boost::asio::buffer(request, 100));std::cout << "成功接收到了客戶端的消息:" << request<<std::endl;std::string reply = "你好客戶端,服務器成功接收到了你的消息";soc.send(boost::asio::buffer(reply, reply.size()));soc.close();}return 0;
}
同步類型的TCP服務器搭建起來相對簡單,首先創建一個上下文對象ioc,然后再創建一個端點對象ep,再創建一個監聽套接字對象ac,創建套接字對象必須要借助上下文對象,這是必須的,至于端點對象,你可以直接將它傳入acceptor的構造函數中,這樣就省略了綁定這一操作了,否則,你需要在創建完ac之后再調用bind函數,將ac和ep進行綁定。(其實acceptor就是一個特殊的套接字對象,本質就是套接字)。
ac.bind(ep);
然后就是接收客戶端的響應了,可以使用receive函數也可以使用read_some函數,發送響應就使用send函數或者write_some函數。
接著就是客戶端代碼。
#include <iostream>
#include<boost/asio.hpp>
int main()
{boost::asio::io_context ioc;boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 3333);boost::asio::ip::tcp::socket soc(ioc);soc.connect(ep);char request[100] = "";std::cin >> request;soc.send(boost::asio::buffer(request, 100));char rce[100] = "";soc.receive(boost::asio::buffer(rce, 100));std::cout << "成功收到了消息:" << rce<<std::endl;char reply[100] = { "你好服務器,這里是客戶端,我們成功收到了消息" };soc.send(boost::asio::buffer(reply, 300));
}
同樣地要先創建上下文,因為創建套接字必須使用上下文對象,然后創建端點對象,并把套接字對象連接到對應的端點進程,這樣客戶端和服務器端就成功連接了,之后用send和recevie函數進行數據讀寫就可以了。
運行代碼,首先運行服務器的代碼。
再運行兩次客戶端代碼,依次輸入1和2,注意先不要回車。
輸入2后進行回車,發現沒有響應,是因為1先連接到了服務器,將線程阻塞了,必須執行完1的程序才會執行2的程序。
再對1進行回車,發現兩個程序都成功執行了。
服務器端也成功接收到了消息。
注意點:使用char數組來接收客戶端發送的消息的主要原因是,Boost.Asio的讀取操作需要一個可變的緩沖區,而char數組提供了這樣的緩沖區。Boost.Asio的讀取操作函數,如read_some()和receive,需要一個可變的緩沖區作為參數,用于存儲從套接字接收的數據。char數組是一種連續的內存塊,可以用于存儲二進制數據,因此在這種情況下非常適合作為緩沖區。另一方面,std::string是一個動態大小的字符序列,它可以自動調整大小以適應不同長度的字符串。雖然std::string也提供了訪問底層字符數組的方法(如`c_str()`和`data()`),但它并不是一個可變的緩沖區,而是一個字符串容器,所以在接收請求的時候更加推薦使用char類型的字符串,并且所有字符串都要初始化為空,不然會中文亂碼。