boost async_read_some 用法
async_read_some讀到數據就會直接回調設置的函數,不管數據是否已經讀完。所以在這裏
會遇到一個非常棘手的問題,如何確定數據已經讀取完畢?常見的方式是在數據的後面添加
標誌位,例如添加/r/n/r/n作為結束符,然後停止讀取
async_read_some的基本原理是往IOCP的隊列裏面添加一個異步任務,沒有事情的時候,CSession::ContinueRead
不應該被調用
class CSession : public boost::enable_shared_from_this<CSession>
{
public:
CSession(boost::asio::io_service &io_service) : m_socket(io_service)
{
memset(m_szRecvBuffer, 0x00, 1024);
m_bStartRecv = false;
}
void Start()
{
static boost::asio::ip::tcp::no_delay option(true);
m_socket.set_option(option);
boost::function0<void> f = boost::bind(&CSession::StartThread, this);
boost::thread thrd(f);
}
/*
啟動線程函數的根本原因是需要向客戶端推送消息,而且在過程中需要等待接收消息
*/
void StartThread()
{
while (true)
{
/*
使用m_bStartRecv標誌位主要是為了避免多次設置回調,當正在接收的時候,不需要設置回調
*/
if (!m_bStartRecv)
{
m_bStartRecv = true;
m_socket.async_read_some(boost::asio::buffer(m_szRecvBuffer),
boost::bind(&CSession::ContinueRead, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
char szAlarm[32] = "alarm";
boost::system::error_code ec;
m_socket.send(boost::asio::buffer(szAlarm), 0, ec);
boost::this_thread::sleep_for(boost::chrono::milliseconds(3000));
if (ec) break;
}
}
private:
/*
在當前接收回調函數中,我們還繼續設置了回調函數m_socket.async_read_some,避免僅僅是讀取數據包的一部分,
在這裏m_szRecvBuffer會一直作為接收的緩沖,而之前接收的數據也在裏面,並且剩下的數據,會根據偏移量,填充到
m_szRecvBuffer的後面,bytes_transferred參數代表當前已經接收的數據
*/
void ContinueRead(const boost::system::error_code &error, std::size_t bytes_transferred)
{
if (error) return;
m_strMatch = m_strMatch + m_szRecvBuffer;
int index = m_strMatch.find("\r\n\r\n", 0);
if (-1 != index)
{
int ret = m_socket.send(boost::asio::buffer(m_szRecvBuffer));
std::cout << m_szRecvBuffer << std::endl;
m_bStartRecv = false;
return;
}
m_socket.async_read_some(boost::asio::buffer((m_szRecvBuffer)),
boost::bind(&CSession::ContinueRead, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
private:
boost::asio::ip::tcp::socket m_socket;
char m_szRecvBuffer[1024];
std::string m_strMatch;
bool m_bStartRecv;
};
註意
當前的僅僅是一個例子,並沒有考慮到客戶端關閉連接,服務器線程及時退出
boost async_read_some 用法