Skip to content

Commit a1f153e

Browse files
committed
add reconnect functionality
1 parent d7f5ceb commit a1f153e

File tree

4 files changed

+117
-45
lines changed

4 files changed

+117
-45
lines changed

src/internal/sio_client_impl.cpp

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sstream>
1111
#include <boost/date_time/posix_time/posix_time.hpp>
1212
#include <mutex>
13+
#include <cmath>
1314
// Comment this out to disable handshake logging to stdout
1415
#if DEBUG || _DEBUG
1516
#define LOG(x) std::cout << x
@@ -27,6 +28,7 @@ namespace sio
2728
m_ping_timeout(0),
2829
m_network_thread(),
2930
m_reconn_attempts(0xFFFFFFFF),
31+
m_reconn_made(0),
3032
m_reconn_delay(5000),
3133
m_reconn_delay_max(25000)
3234
{
@@ -57,25 +59,6 @@ namespace sio
5759
sync_close();
5860
}
5961

60-
// Websocket++ client client
61-
void client_impl::on_fail(connection_hdl con)
62-
{
63-
m_con.reset();
64-
m_con_state = con_closed;
65-
this->sockets_invoke_void(&sio::socket::on_disconnect);
66-
LOG("Connection failed." << std::endl);
67-
if(m_fail_listener)m_fail_listener();
68-
}
69-
70-
void client_impl::on_pong()
71-
{
72-
if(m_ping_timeout_timer)
73-
{
74-
m_ping_timeout_timer->cancel();
75-
m_ping_timeout_timer.reset();
76-
}
77-
}
78-
7962
void client_impl::on_handshake(message::ptr const& message)
8063
{
8164
if(message && message->get_flag() == message::flag_object)
@@ -113,19 +96,43 @@ namespace sio
11396
m_ping_timer->expires_from_now(milliseconds(m_ping_interval), ec);
11497
if(ec)LOG("ec:"<<ec.message()<<std::endl);
11598
m_ping_timer->async_wait(lib::bind(&client_impl::__ping,this,lib::placeholders::_1));
116-
LOG("On handshake,sid:"<<m_sid<<",ping interval:"<<m_ping_interval<<",ping timeout"<<"m_ping_timeout"<<m_ping_timeout<<std::endl);
99+
LOG("On handshake,sid:"<<m_sid<<",ping interval:"<<m_ping_interval<<",ping timeout"<<m_ping_timeout<<std::endl);
117100
return;
118101
}
119102
failed:
120103
//just close it.
121104
m_client.get_io_service().dispatch(lib::bind(&client_impl::__close, this,close::status::policy_violation,"Handshake error"));
122105
}
106+
107+
// Websocket++ client client
108+
void client_impl::on_fail(connection_hdl con)
109+
{
110+
m_con.reset();
111+
m_con_state = con_closed;
112+
this->sockets_invoke_void(&sio::socket::on_disconnect);
113+
LOG("Connection failed." << std::endl);
114+
if(m_reconn_made<m_reconn_attempts)
115+
{
116+
LOG("Reconnect for attempt:"<<m_reconn_made<<std::endl);
117+
unsigned delay = this->next_delay();
118+
if(m_reconnect_listener) m_reconnect_listener(m_reconn_made,delay);
119+
m_reconn_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service()));
120+
boost::system::error_code ec;
121+
m_reconn_timer->expires_from_now(milliseconds(delay), ec);
122+
m_reconn_timer->async_wait(lib::bind(&client_impl::reconnect,this,lib::placeholders::_1));
123+
}
124+
else
125+
{
126+
if(m_fail_listener)m_fail_listener();
127+
}
128+
}
123129

124130
void client_impl::on_open(connection_hdl con)
125131
{
126132
LOG("Connected." << std::endl);
127133
m_con_state = con_opened;
128134
m_con = con;
135+
m_reconn_made = 0;
129136
this->sockets_invoke_void(&sio::socket::on_open);
130137
if(m_open_listener)m_open_listener();
131138
}
@@ -156,12 +163,22 @@ namespace sio
156163
else
157164
{
158165
this->sockets_invoke_void(&sio::socket::on_disconnect);
166+
if(m_reconn_made<m_reconn_attempts)
167+
{
168+
LOG("Reconnect for attempt:"<<m_reconn_made<<std::endl);
169+
unsigned delay = this->next_delay();
170+
if(m_reconnect_listener) m_reconnect_listener(m_reconn_made,delay);
171+
m_reconn_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service()));
172+
boost::system::error_code ec;
173+
m_reconn_timer->expires_from_now(milliseconds(delay), ec);
174+
m_reconn_timer->async_wait(lib::bind(&client_impl::reconnect,this,lib::placeholders::_1));
175+
return;
176+
}
159177
reason = client::close_reason_drop;
160178
}
161179

162180
if(m_close_listener)
163181
{
164-
165182
m_close_listener(reason);
166183
}
167184
}
@@ -177,6 +194,15 @@ namespace sio
177194
m_packet_mgr.put_payload(msg->get_payload());
178195
}
179196

197+
void client_impl::on_pong()
198+
{
199+
if(m_ping_timeout_timer)
200+
{
201+
m_ping_timeout_timer->cancel();
202+
m_ping_timeout_timer.reset();
203+
}
204+
}
205+
180206
void client_impl::on_pong_timeout()
181207
{
182208
LOG("Pong timeout"<<std::endl);
@@ -257,6 +283,11 @@ namespace sio
257283
void client_impl::__close(close::status::value const& code,std::string const& reason)
258284
{
259285
LOG("Close by reason:"<<reason << std::endl);
286+
if(m_reconn_timer)
287+
{
288+
m_reconn_timer->cancel();
289+
m_reconn_timer.reset();
290+
}
260291
if (m_con.expired())
261292
{
262293
std::cerr << "Error: No active session" << std::endl;
@@ -286,6 +317,12 @@ namespace sio
286317
m_network_thread.reset();
287318
}
288319
}
320+
321+
unsigned client_impl::next_delay() const
322+
{
323+
//no jitter, fixed power root.
324+
return (unsigned)min(m_reconn_delay * pow(1.5,m_reconn_made),m_reconn_delay_max);
325+
}
289326

290327
void client_impl::send(packet& p)
291328
{
@@ -392,6 +429,11 @@ namespace sio
392429

393430
void client_impl::connect(const std::string& uri)
394431
{
432+
if(m_reconn_timer)
433+
{
434+
m_reconn_timer->cancel();
435+
m_reconn_timer.reset();
436+
}
395437
if(m_network_thread)
396438
{
397439
if(m_con_state == con_closing||m_con_state == con_closed)
@@ -400,6 +442,7 @@ namespace sio
400442
//if client is closed, still need to join,
401443
//but in closed case,join will return immediately.
402444
m_network_thread->join();
445+
m_network_thread.reset();//defensive
403446
}
404447
else
405448
{
@@ -408,33 +451,30 @@ namespace sio
408451
}
409452
}
410453
m_con_state = con_opening;
454+
m_base_url = uri;
455+
m_reconn_made = 0;
411456
this->reset_states();
412457
m_client.get_io_service().dispatch(lib::bind(&client_impl::__connect,this,uri));
413458
m_network_thread.reset(new std::thread(lib::bind(&client_impl::run_loop,this)));//uri lifecycle?
414459

415460
}
416461

417-
// void client_impl::reconnect(const std::string& uri)
418-
// {
419-
// if(m_network_thread)
420-
// {
421-
// if(m_con_state == con_closing)
422-
// {
423-
// m_network_thread->join();
424-
// }
425-
// else
426-
// {
427-
// return;
428-
// }
429-
// }
430-
// if(m_con_state == con_closed)
431-
// {
432-
// m_con_state = con_opening;
433-
434-
// m_client.get_io_service().dispatch(lib::bind(&client_impl::__connect,this,uri));
435-
// m_network_thread.reset(new std::thread(lib::bind(&client_impl::run_loop,this)));//uri
436-
// }
437-
// }
462+
void client_impl::reconnect(boost::system::error_code const& ec)
463+
{
464+
if(ec)
465+
{
466+
return;
467+
}
468+
if(m_con_state == con_closed)
469+
{
470+
m_con_state = con_opening;
471+
m_reconn_made++;
472+
this->reset_states();
473+
LOG("Reconnecting..."<<std::endl);
474+
if(m_reconnecting_listener) m_reconnecting_listener();
475+
m_client.get_io_service().dispatch(lib::bind(&client_impl::__connect,this,m_base_url));
476+
}
477+
}
438478

439479
socket::ptr const& client_impl::socket(std::string const& nsp)
440480
{

src/internal/sio_client_impl.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ void set_##__FIELD__(__TYPE__ const& l) \
5757
SYNTHESIS_SETTER(client::con_listener,open_listener)
5858

5959
SYNTHESIS_SETTER(client::con_listener,fail_listener)
60+
61+
SYNTHESIS_SETTER(client::reconnect_listener,reconnect_listener)
62+
63+
SYNTHESIS_SETTER(client::con_listener,reconnecting_listener)
6064

6165
SYNTHESIS_SETTER(client::close_listener,close_listener)
6266

@@ -72,6 +76,8 @@ void set_##__FIELD__(__TYPE__ const& l) \
7276
m_open_listener = nullptr;
7377
m_close_listener = nullptr;
7478
m_fail_listener = nullptr;
79+
m_reconnect_listener = nullptr;
80+
m_reconnecting_listener = nullptr;
7581
}
7682

7783
void clear_socket_listeners()
@@ -83,8 +89,6 @@ void set_##__FIELD__(__TYPE__ const& l) \
8389
// Client Functions - such as send, etc.
8490
void connect(const std::string& uri);
8591

86-
// void reconnect(const std::string& uri);
87-
8892
socket::ptr const& socket(const std::string& nsp);
8993

9094
// Closes the connection
@@ -129,6 +133,10 @@ void set_##__FIELD__(__TYPE__ const& l) \
129133
socket::ptr get_socket_locked(std::string const& nsp);
130134

131135
void sockets_invoke_void(void (sio::socket::*fn)(void));
136+
137+
void reconnect(boost::system::error_code const& ec);
138+
139+
unsigned next_delay() const;
132140

133141
void run_loop();
134142

@@ -155,6 +163,8 @@ void set_##__FIELD__(__TYPE__ const& l) \
155163
client_type m_client;
156164
// Socket.IO server settings
157165
std::string m_sid;
166+
std::string m_base_url;
167+
158168
unsigned int m_ping_interval;
159169
unsigned int m_ping_timeout;
160170

@@ -165,11 +175,16 @@ void set_##__FIELD__(__TYPE__ const& l) \
165175
std::unique_ptr<boost::asio::deadline_timer> m_ping_timer;
166176

167177
std::unique_ptr<boost::asio::deadline_timer> m_ping_timeout_timer;
178+
179+
std::unique_ptr<boost::asio::deadline_timer> m_reconn_timer;
168180

169181
con_state m_con_state;
170182

171183
client::con_listener m_open_listener;
172184
client::con_listener m_fail_listener;
185+
client::con_listener m_reconnecting_listener;
186+
client::reconnect_listener m_reconnect_listener;
187+
173188
client::close_listener m_close_listener;
174189

175190
client::socket_listener m_socket_open_listener;
@@ -184,6 +199,8 @@ void set_##__FIELD__(__TYPE__ const& l) \
184199
unsigned m_reconn_delay_max;
185200

186201
unsigned m_reconn_attempts;
202+
203+
unsigned m_reconn_made;
187204

188205
friend class sio::client;
189206
friend class sio::socket;

src/sio_client.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,21 @@ namespace sio
3838
m_impl->set_close_listener(l);
3939
}
4040

41-
4241
void client::set_socket_open_listener(socket_listener const& l)
4342
{
4443
m_impl->set_socket_open_listener(l);
4544
}
4645

46+
void client::set_reconnect_listener(reconnect_listener const& l)
47+
{
48+
m_impl->set_reconnect_listener(l);
49+
}
50+
51+
void client::set_reconnecting_listener(con_listener const& l)
52+
{
53+
m_impl->set_reconnecting_listener(l);
54+
}
55+
4756
void client::set_socket_close_listener(socket_listener const& l)
4857
{
4958
m_impl->set_socket_close_listener(l);

src/sio_client.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace sio
2626
typedef std::function<void(void)> con_listener;
2727

2828
typedef std::function<void(close_reason const& reason)> close_listener;
29+
30+
typedef std::function<void(unsigned, unsigned)> reconnect_listener;
2931

3032
typedef std::function<void(std::string const& nsp)> socket_listener;
3133

@@ -37,6 +39,10 @@ namespace sio
3739

3840
void set_fail_listener(con_listener const& l);
3941

42+
void set_reconnecting_listener(con_listener const& l);
43+
44+
void set_reconnect_listener(reconnect_listener const& l);
45+
4046
void set_close_listener(close_listener const& l);
4147

4248
void set_socket_open_listener(socket_listener const& l);

0 commit comments

Comments
 (0)