天天看點

boost::asio(1)

剛出差回來,發現我們又有好久都沒有更新新東西了,好吧,本來打算好好休息的。但是想想趁着休息,簡單給大家說一些新東西——boost的asio。

在很久以前大家就比較對boost的内容比較感興趣,但是當時因為考慮到我們的标準庫都還沒有和大家說完,也就一拖再拖,那麼,既然标準庫以及一些C++的正常知識都和大家說了,現在也該是我們聊一些新鮮内容的時候了。

在C++網絡程式設計的子產品裡面,asio不算最有名的,但也基本是夠用的,當然重要是還是因為他的簡單,如果大家有興趣,網上一搜boost的asio,相信能夠找到大把的資料,是以這裡我們用一個例子給大家示範一下asio的網絡程式設計,那麼今天我們要說的是一個服務端的程式設計(先說完服務端再來說用戶端,因為相對服務端來說,用戶端就相對簡單得多),這個伺服器的功能不多,這是因為公司項目而生的,是以都隻有一些對應的功能,但用來作為學習用的demo已經足夠。

在說網絡程式設計之前,我們要先了解一個東西——定時器(deadline_time),要使用這個東西我們需要包含<boost/data_time/posix_time/posix_time.hpp>頭檔案,同時我們還需要引入io_service,是以還需要添加一個<boost/asio.hpp>頭檔案,他們都在名字空間boost::asio中,這裡簡單的示範一下這個東西的用法,讓大家有個眼熟,因為在接下來的用戶端程式設計中,我們會将他運用在異步等待上面。

在異步定時中deadline_time需要一個等待回調函數,這個函數的原型大概就是這樣:

//========================================================

void(LPFUN*)(const boost::system::error_code&);

從參數我們可以看得出,如果發生錯誤的話,那麼會有相關的作業系統的錯誤碼發生,是以我們可以檢測這個參數以便知道是否有錯誤發生。我們還是來個簡單的demo:

//=================================================================

#include <boost/asio>

#include <boost/data_time/posix_time/posix_time.hpp>

#include <iostream>

//---------------------------

// 異步等待回調函數

void waitHandle(const boost::system::error_code& e){

if(e){

std::cerr<<"have a error happen..."<<std::endl;

}

else{

std::cerr<<"wait finish..."<<std::endl;

}

int main(){

using namespace boost::asio;

io_service io;

deadline_time t(io,posix_time_seconds(5));

t.async_wait(waitHandle);

std::cerr<<"waiting .... <<std::endl;

io.run();

return 0;

//==============================================

運作程式,我們會看到在列印waiting .... 之後大約5s的時候才會列印出wait finish....看到這個結果後大家是不是對他的作用有了一些了解了呢?

嗯,給大家示範了一下定時器的異步等待功能還有一個用處就是讓大家了解一下asio中的異步操作所需要的一些東西:

1. io_service需要開啟消息循環模式(簡單點說也就是需要調用io_service::run)

2. 需要一個異步操作句柄(例如上面的waitHandle)

在對asio的異步模型有所了解之後那麼我們就可以看看怎麼使用boost的asio來寫一個簡單的伺服器了:

//======================================================

#pragma once

#include <boost/asio.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

#include <memory>

#include <functional>

#include <vector>

#include <algorithm>

#include <thread>

#include <boost/algorithm/string.hpp>

#define MAX_DATA 8192000 //單次最大發送8M資料

using namespace boost;

typedef std::shared_ptr<ip::tcp::socket> Sock_Ptr;

typedef std::shared_ptr<std::vector<char>> Buffer;

typedef std::function<void(const std::string,Sock_Ptr)> Msg_Proc_Fun;

class HService

{

public:

HService(unsigned port = 12000);

virtual ~HService();

//服務端可以是單例

static std::shared_ptr<HService> Instance(){

static std::shared_ptr<HService> _ptr(new HService);

return _ptr;

}

//同步操作

int Send(const std::string& str,Sock_Ptr sock);

int Read(std::string& str, Sock_Ptr sock);

//異步操作

void PostRecive(Sock_Ptr sock);

void PostSend(const std::string& str,Sock_Ptr sock);

//開啟線程,異步循環處理消息

void run();

//=============================================

// 将自己的消息處理函數綁定過來處理消息

void bindProcMsgFun(Msg_Proc_Fun fun);

protected:

void start();

//================================================

// 異步接收回調函數

void accept_handle(const boost::system::error_code& e,Sock_Ptr sock);

// 異步發送回調函數

void Send_handle(const boost::system::error_code& e, Sock_Ptr sock, std::string &str);

// 異步讀取回調函數

void Read_handle(const boost::system::error_code& e,Sock_Ptr sock,Buffer rdbuffer);

void startthread();

private:

io_service m_ios;

unsigned n_port; //開啟服務端口

ip::tcp::endpoint m_port; //伺服器的端口,需要一個ip和端口構造

ip::tcp::acceptor m_acceptor;//接收器,所有想要通路的該伺服器的socket都需要他來處理

std::thread  m_thread;

Msg_Proc_Fun m_msg_recall_fun; //隻處理網絡接收到的資訊

std::shared_ptr<io_service::work> m_work;

};

//----------------------------------------

#include "HService.h"

HService::HService(unsigned port) :

n_port(port), m_port(ip::tcp::v4(),

n_port), m_msg_proc_fun(nullptr), m_acceptor(m_ios, m_port),

m_msg_recall_fun(nullptr)

m_work = std::shared_ptr<boost::asio::io_service::work>(new boost::asio::io_service::work(m_ios));

start();

HService::~HService()

if (m_thread.joinable())

m_thread.join();

void HService::start()

Sock_Ptr sock = Sock_Ptr(new ip::tcp::socket(m_ios));

m_acceptor.async_accept(*sock, std::bind(&HService::accept_handle, this,

std::placeholders::_1, sock));

int HService::Send(const std::string &str, Sock_Ptr sock)

if (str.empty() || sock._Expired())

return 0;

static int count = 0;

boost::system::error_code e;

int ret = sock->send(buffer(&str[0], str.length()), 0, e);

if (e){

if (count == 5){

if (m_msg_proc_fun)

m_msg_proc_fun("消息發送失敗,請檢查網絡是否出現異常!!!",sock);

std::cout << "消息發送失敗!!!!!\n";

sock->close(); //關閉連接配接

count = 0;

return -1;

}

else{

m_msg_proc_fun("消息發送失敗,将進行重新發送......", sock);

std::cout << "消息發送失敗,将進行重新發送......\n";

//等待1秒,重發消息

asio::deadline_timer t(m_ios, posix_time::seconds(1));

t.wait();

++count;

Send(str, sock);

else{

if (m_msg_proc_fun)

m_msg_proc_fun("消息發送成功!!!!!", sock);

std::cout << "消息發送成功!!!!\n";

count = 0;

return ret;

return -1;

int HService::Read(std::string &str, Sock_Ptr sock)

Buffer rdbuffer = Buffer(new std::vector<char>(409600, 0));

int ret = sock->receive(buffer(*rdbuffer), 0, e);

m_msg_proc_fun("接收消息失敗!!!!!", sock);

std::cout << "接收消息失敗!!!!!" << std::endl;

return -1;

m_msg_proc_fun("接收消息成功!!!!!", sock);

std::cout << "接收消息成功!!!!!" << std::endl;

str = std::string(&(*rdbuffer)[0]);

m_msg_proc_fun(str, sock);

std::cout << str << std::endl;

void HService::PostRecive(hlw::Sock_Ptr sock)

sock->async_read_some(buffer(*rdbuffer), std::bind(&HService::Read_handle, this,

std::placeholders::_1, sock, rdbuffer));

void HService::PostSend(const std::string &str, hlw::Sock_Ptr sock)

if (str.empty())

return;

sock->async_send(buffer(&str[0], str.length()), std::bind(&HService::Send_handle, this,

std::placeholders::_1, sock, str));

void HService::run()

m_thread = std::thread(&HService::startthread, this);

void HService::bindProcMsgFun(hlw::Msg_Proc_Fun fun)

m_msg_recall_fun = fun;

void HService::accept_handle(const boost::system::error_code &e, hlw::Sock_Ptr sock)

m_msg_proc_fun("錯誤:接收用戶端連接配接失敗!!!!!", sock);

m_msg_proc_fun("客戶連接配接成功!!!", sock);

std::cout << "Client:\n" << sock->remote_endpoint().address() << std::endl;

PostRecive(sock);

start();

void HService::Send_handle(const boost::system::error_code &e

, Sock_Ptr sock, std::string& str)

sock->close();

m_msg_proc_fun("發送消息失敗,正在重新發送.....", sock);

std::cout << "發送消息失敗......\n";

//重新發送

PostSend(str, sock);

m_msg_proc_fun("發送消息成功!!!!", sock);

str.clear();

{

std::string temp;

std::swap(str, temp);

std::cout << "\n發送消息成功!!!!" << std::endl;

//投遞一個接收

if (sock.use_count() <= 5)

PostRecive(sock);

void HService::Read_handle(const boost::system::error_code &e,

hlw::Sock_Ptr sock, Buffer rdbuffer)

std::cout << "消息接收失敗!!!!!\n";

std::string str = std::string(&(*rdbuffer)[0]);

if (m_msg_recall_fun)

m_msg_recall_fun(str, sock);

void HService::startthread()

for (int i = 0; i < 8; ++i){

std::thread th([&](){m_ios.run(); });

th.detach();

//=======================================================

關于異步操作有一個特點,那就是無論何時我們要保證有一個接收操作在執行,因為他不同于同步操作,同步操作的話隻有想要的時候去接收直到接收完成後才完成操作,而異步是由作業系統負責,是以你永遠不知道你的資訊什麼時候會來,是以我們需要保證無論何時有資訊來我們都要能夠接收和處理,也就是大家看到的為什麼我們總是随時保持着PostRecive這個操作的原因。

ok,這個服務端算是完成,對了,C++不同于python這些腳本語言,是以我不能三句兩句就給大家搞出一個東西出來,我所能夠做的就是示範C++一些子產品的用法...

由于這個子產品需要配合用戶端的使用,是以等我們将用戶端的程式寫出來後再一起看用法....

c++
上一篇: boost.asio
下一篇: boost::asio(3)

繼續閱讀