C++实现服务器压力测试框架
flyfish 2015-3-9
#pragma once #include <boost/asio.hpp> #include <boost/array.hpp> #include <boost/bind.hpp> #include <boost/asio/deadline_timer.hpp> #include <boost/enable_shared_from_this.hpp> class CSession: public boost::enable_shared_from_this<CSession> { public: CSession(const std::string IP, unsigned short port,int m_heartbeat_timer_minutes,boost::asio::io_service& io_service_); ~CSession(void); private: boost::asio::ip::tcp::endpoint m_ep; boost::asio::ip::tcp::socket m_sock; boost::asio::ip::tcp::resolver m_resolver; boost::array<unsigned char, 4096> read_buffer; boost::array<unsigned char, 4096> write_buffer; boost::asio::deadline_timer heartbeat_timer; int m_heartbeat_timer_minutes;//心跳间隔 以分为单位 void receive_handler(const boost::system::error_code &ec, std::size_t bytes_transferred);//接收数据处理结果 void connect_handler(const boost::system::error_code &ec); //连接处理结果 void heartbeat_handler(const boost::system::error_code &ec); //心跳处理结果 void login_handler(const boost::system::error_code &ec,std::size_t bytes_transferred);//登录结果的处理 void start_receive();//开始接收数据 void send_handler(const boost::system::error_code &ec); std::size_t check_frame(const boost::system::error_code &ec, std::size_t bytes_transferred);//校验数据 void parse_frame(const boost::system::error_code &ec, std::size_t bytes_transferred);//解析数据 public: void start_send();//其他地方调用时 只需要把任务加到任务队列 执行 io_service_.post(boost::bind(&CSession::start_send, this)); void start();//启动停止 void stop(); void login();//登录 void heartbeat();//心跳 task m_task_queue;//线程安全的任务队列 };
实现文件
#include "Session.h" CSession::CSession( const std::string IP, unsigned short port, int heartbeat_timer_minutes, boost::asio::io_service& io_service_) : m_resolver(io_service_), m_sock(io_service_), heartbeat_timer(io_service_), m_nConnectState(0), m_ep(boost::asio::ip::address::from_string(IP),port), m_pObj(nullptr), m_heartbeat_timer_minutes(heartbeat_timer_minutes), m_nHeartbeatCount(0) { read_buffer.fill(0); } void CSession::start() { m_sock.async_connect(m_ep, boost::bind(&CSession::connect_handler, shared_from_this(), boost::asio::placeholders::error)); } CSession::~CSession(void) { stop(); } void CSession::stop() { heartbeat_timer.cancel(); m_sock.close(); } std::size_t CSession::check_frame(const boost::system::error_code &ec, std::size_t bytes_transferred) { //bytes_transferred 已经接收的字节数 //返回0 表示 验证通过 //返回1 表示 需要继续验证 } void CSession::parse_frame(const boost::system::error_code &ec, std::size_t bytes_transferred) { if (!ec) { } } void CSession::start_receive() { m_sock.async_receive(boost::asio::buffer(read_buffer), boost::bind(&CSession::receive_handler, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void CSession::receive_handler(const boost::system::error_code &ec, std::size_t bytes_transferred) { if (!ec) { //check_frame 验证接收的数据,当验证成功时,开始 boost::asio::async_read(m_sock,boost::asio::buffer(read_buffer), boost::bind(&CSession::check_frame, shared_from_this(), boost::asio::placeholders::error, bytes_transferred), boost::bind(&CSession::parse_frame, shared_from_this(), boost::asio::placeholders::error, bytes_transferred)); m_sock.async_receive(boost::asio::buffer(read_buffer), boost::bind(&CSession::receive_handler, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { stop(); } } void CSession::heartbeat() { unsigned char c[256]; UINT nLen = process_hartbeat(c);//生成心跳数据 m_sock.async_write_some(boost::asio::buffer(c,nLen),boost::bind(&CSession::heartbeat_handler,shared_from_this(),boost::asio::placeholders::error)); } void CSession::heartbeat_handler(const boost::system::error_code &ec) { if (!ec) { heartbeat_timer.expires_from_now(boost::posix_time::minutes(m_heartbeat_timer_minutes)); heartbeat_timer.async_wait(boost::bind(&CSession::heartbeat,shared_from_this())); } else { stop(); } } void CSession::login()//登录 { //连接完成 发送登录帧 //******************************************************************************************* unsigned char c[256]; UINT nLen = process_login(c);//生成登录数据 例如 c中存储了用户名称和密码等 m_sock.async_write_some(boost::asio::buffer(c,nLen),boost::bind(&CSession::login_handler, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void CSession::login_handler(const boost::system::error_code &ec,std::size_t bytes_transferred) { if (!ec) { start_receive();//启动接收 heartbeat(); } else { stop(); } } void CSession::connect_handler(const boost::system::error_code &ec) { if (!ec) { boost::this_thread::sleep(boost::posix_time::microseconds(500)); login();//连接成功之后开始登录 } else { boost::this_thread::sleep(boost::posix_time::microseconds(60000)); start();//连接失败 需要再次连接 } } void CSession::start_send() { //从线程安全的任务队列中获取一个任务开始发送 std::tuple<bool,task> ret=m_task_queue.get_nonblock(); if (std::get<0>(ret)) { unsigned char* c=std::get<1>(ret).data; int nLen=std::get<1>(ret).len; /**************************************************************************************************/ m_sock.async_write_some(boost::asio::buffer(c,nLen),boost::bind(&CSession::send_handler, shared_from_this(), boost::asio::placeholders::error)); } } void CSession::send_handler(const boost::system::error_code &ec) { if (!ec) { start_send();//任务队列不为空时,开始发送下一个任务 } }
class client { public: boost::shared_ptr<CSession> m_pSocket;//创建继承于enable_shared_from_this类的对象时必须使用智能指针 }; std::vector<client> client_queue;//存储生成的客户端实例 boost::asio::io_service m_io_service; boost::asio::io_service::work m_work(m_io_service);//即使io任务完成,也不退出 std::string IP="192.168.1.1"; unsigned short port=8000; int heartbeat=10; for (int i=0;i<client_queue.size();i++) { boost::shared_ptr<CSession>p (new CSession(IP,port,heartbeat,(m_io_service))); client_queue.at(i)->m_pSocket->start(); } boost::thread t(boost::bind(&boost::asio::io_service::run,boost::ref(m_io_service)));
多线程调用run方式
int thread_count=(std::max)(static_cast<int>(boost::thread::hardware_concurrency()),1);//至少有一个线程运行 boost::thread_group tg; for (int i=0;i<thread_count;i++) { tg.create_thread(boost::bind(&boost::asio::io_service::run,boost::ref(m_io_service))); boost::this_thread::sleep(boost::posix_time::seconds(5)); }