在使用同步client的时候,有时候会出现一种情况,可以成功打开客户端链接,但是数据发过去之后,很长时间收不到返回值,这个时候就会将进程或者线程阻住,影响其它业务的执行,所以想到用一个异步定时器,来控制超时,定时器代码实现如下:
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
test.cpp
#include
#include
#include
using namespace std;
/*
* 定时器类
* */
class std_timer
{
public:
std_timer() :expired_(true), try_to_expire_(false)
{
}
std_timer(const std_timer& t)
{
expired_ = t.expired_.load();
try_to_expire_ = t.try_to_expire_.load();
}
~std_timer()
{
Expire();
//std::cout << "timer destructed!" << std::endl;
}
void StartTimer(int interval, std::function task)
{
if (expired_ == false)
{
//std::cout << "timer is currently running, please expire it first..." << std::endl;
return;
}
expired_ = false;
std::thread([this, interval, task]()
{
while (!try_to_expire_)
{
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
task();
}
//std::cout << "stop task..." << std::endl;
{
std::lock_guard locker(mutex_);
expired_ = true;
expired_cond_.notify_one();
}
}).detach();
}
void Expire()
{
if (expired_) return;
if (try_to_expire_)
{
//std::cout << "timer is trying to expire, please wait..." << std::endl;
return;
}
try_to_expire_ = true;
{
std::unique_lock locker(mutex_);
expired_cond_.wait(locker, [this] {return expired_ == true; });
if (expired_ == true) {
// std::cout << "timer expired!" << std::endl;
try_to_expire_ = false;
}
}
}
template
void SyncWait(int after, callable&& f, arguments&&... args)
{
std::function::type()> task
(std::bind(std::forward(f), std::forward(args)...));
std::this_thread::sleep_for(std::chrono::milliseconds(after));
task();
}
template
void AsyncWait(int after, callable&& f, arguments&&... args)
{
std::function::type()> task
(std::bind(std::forward(f), std::forward(args)...));
std::thread([after, task]() {
std::this_thread::sleep_for(std::chrono::milliseconds(after));
task();
}).detach();
}
private:
std::atomic expired_;
std::atomic try_to_expire_;
std::mutex mutex_;
std::condition_variable expired_cond_;
};
//void EchoFunc(std::string&& s) {
// std::cout << "test : " << s << endl;
//}
//
//int main_timer_std() {
// Timer t;
// //周期性执行定时任务
// t.StartTimer(1000, std::bind(EchoFunc, "hello world!"));
// std::this_thread::sleep_for(std::chrono::seconds(4));
// std::cout << "try to expire timer!" << std::endl;
// t.Expire();
//
// //周期性执行定时任务
// t.StartTimer(1000, std::bind(EchoFunc, "hello c++11!"));
// std::this_thread::sleep_for(std::chrono::seconds(4));
// std::cout << "try to expire timer!" << std::endl;
// t.Expire();
//
// std::this_thread::sleep_for(std::chrono::seconds(2));
//
// //只执行一次定时任务
// //同步
// t.SyncWait(1000, EchoFunc, "hello world!");
// //异步
// t.AsyncWait(1000, EchoFunc, "hello c++11!");
//
// std::this_thread::sleep_for(std::chrono::seconds(2));
//
// return 0;
//}
实现一个定时器很简单,不做赘述,然后再写一下asio同步客户端的实现:
#pragma once
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601
#endif
#include
#include
#include
#include
由于boost的asio库,在编译的时候有时会跟其它第三方库有冲突,导致出现很多编译问题,所以再在上层封装一层使用类:
#pragma once
#include
#include
#include
namespace BoostSocket
{
//同步客户端使用接口
namespace SyncClient
{
class ClientManager;
class Client;
class ClientOper
{
public:
virtual ~ClientOper() {}
int OpenClient(const std::string& host_name, const std::string & port);
void CloseClient();
int SendData(const char* _buffer, std::size_t read_len);
int RecvData(char* data, std::size_t data_len);
private:
ClientManager* oper_obj_;
Client* client_obj_;
};
}
}//namespace BoostSocket
#include "Boost_Socket_Oper.h"
#include "Client.h"
///
*同步客户端*
//
int BoostSocket::SyncClient::ClientOper::OpenClient(const std::string & host_name, const std::string & port)
{
try {
oper_obj_ = new BoostSocket::SyncClient::ClientManager;
// 构建Server实例
client_obj_ = oper_obj_->get_client(host_name, port);
}
catch (std::exception& _e) {
std::cout << _e.what() << std::endl;
return -1;
}
return 0;
}
void BoostSocket::SyncClient::ClientOper::CloseClient()
{
if (client_obj_ != nullptr)
{
delete client_obj_;
client_obj_ = nullptr;
}
}
int BoostSocket::SyncClient::ClientOper::SendData(const char* _buffer, std::size_t read_len)
{
int nret = 0;
try
{
nret = client_obj_->SendData(_buffer, read_len);
}
catch (std::exception& _e) {
std::cout << _e.what() << std::endl;
nret = -1;
}
return nret;
}
int BoostSocket::SyncClient::ClientOper::RecvData(char* data, std::size_t data_len)
{
int nret = 0;
try
{
nret = client_obj_->RecvData(data, data_len);
}
catch (std::exception& _e) {
std::cout << _e.what() << std::endl;
nret = -1;
}
return nret;
}
封装好之后,我们就可以利用定时器来实现超时检测了, 测试代码如下:
using BoostSocket::SyncClient::ClientOper;
void time_out(ClientOper* client) {
client->CloseClient();
}
int main(void)
{
char request[1024] = { 0 };
char reply[1024] = { 0 };
std::vector pBuf;
std::size_t request_length = 0;
do {
std::cout << "Enter message: ";
std::cin.getline(request, 1024);
request_length = std::strlen(request);
} while (request_length == 0);
ClientOper client;
int n = client.OpenClient("172.20.26.152", "13588");
if (n < 0)
{
std::cout << "打开客户端失败!" << std::endl;
client.CloseClient();
system("pause");
return -1;
}
int nret = client.SendData(request, request_length);
if (nret < 0)
{
std::cout << "发送数据失败!" << std::endl;
client.CloseClient();
system("pause");
return -1;
}
std_timer timer;
//同步
timer.AsyncWait(3000, time_out, &client);
int nlen = client.RecvData(reply, request_length);
if (nlen < 0)
{
std::cout << "接收数据失败!" << std::endl;
client.CloseClient();
system("pause");
return -1;
}
std::cout << reply << std::endl;
std::cout << nret << " " << nlen << std::endl;
client.CloseClient();
system("pause");
return 0;
}
在超时回调里可以将链接关闭重新打开,或者一些其它操作,来中断接收数据,这样就可以实现超时操作了。在项目中测试通过。