客户端的需求:具备读/写能力,能自动重连。
自动重连用一个线程去检测,读/写能力复用RWHandler。
客户端的实现如下:
class Connector
{
public:
Connector(io_service& ios, const string& strIP, short port) : m_ios(ios), m_socket(ios), m_serverAddr(tcp::endpoint(address::from_string(strIP), port)), m_isConnected(false), m_chkThread(nullptr)
{
CreateEventHandler(ios);
}
~Connector()
{
}
bool Start()
{
m_eventHandler->GetSocket().async_connect(m_serverAddr, [this](const boost::system::error_code& error){
if (error) {
HandleConnectError(error);
return ;
}
cout << "connect ok" << endl;
m_isConnected = true;
// 连接成功后发起一个异步读操作
m_eventHandler->HandleRead();
});
boost::this_thread::sleep(boost::posix_time::seconds(1));
return m_isConnected;
}
bool IsConnected() const
{
return m_isConnected;
}
void Send(char* data, int len)
{
if(!m_isConnected) {
return ;
}
// 同步写
m_eventHandler->HandleWrite(data, len);
}
private:
void CreateEventHandler(io_service& ios)
{
m_eventHandler = std::make_shared<RWHandler>(ios);
m_eventHandler->SetCallBackError([this](int connid){
HandleRWError(connid);
});
}
void HandleRWError(int connid)
{
m_isConnected = false;
CheckConnnect();
}
void HandleConnectError(const boost::system::error_code &error)
{
m_isConnected = false;
cout << error.message() << endl;
m_eventHandler->CloseSocket();
CheckConnect();
}
void CheckConnect()
{
if (m_chkThread != nullptr) {
return;
}
m_chkThread = std::make_shared<std::thread>([this]{
while(true) {
if(!IsConnected()) {
Start();
}
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
});
}
private:
io_service& m_ios;
tcp::socket m_socket;
// 服务端地址
tcp::endpoint m_serverAddr;
std::shared_ptr<RWHandler> m_eventHandler;
bool m_isConnected;
// 专门检测重连的线程
std::shared_ptr<std::thread> m_chkThread;
};
连接成功后发起了一个异步读操作,它用来判断连接是否断开,因为当连接断开时,HandleRWError会触发重连操作。
客户端的测试代码如下:
int main()
{
io_service ios;
boost::asio::io_service::work work(ios);
boost::thread thd([&ios]{
ios.run();
});
Connector conn(ios, "127.0.0.1", 9900);
conn.Start();
istring str;
if (!conn.IsConnected()) {
cin >> str;
return -1;
}
const int len = 512;
char line[len] = "";
while(cin >> str) {
char header[HEAD_LEN] = {};
// str末尾'/0'
int totalLen = str.length() + 1 + HEAD_LEN;
std::sprintf(header, "%d", totalLen);
memcpy(line, header, HEAD_LEN);
memcpy(line + HEAD_LEN, str.c_str(), str.length() + 1);
conn.Send(line, totalLen);
}
return 0;
}
注意:这里通过boost::asio::io_service::work和单独线程来保证ios::run()不退出。