st_asio_wrapper_connector.h 5.4 KB
Newer Older
1 2 3 4 5
/*
 * st_asio_wrapper_connector.h
 *
 *  Created on: 2012-3-2
 *      Author: youngwolf
6 7 8
 *		email: mail2tao@163.com
 *		QQ: 676218192
 *		Community on QQ: 198941541
9 10 11 12 13 14 15
 *
 * this class only used at client endpoint
 */

#ifndef ST_ASIO_WRAPPER_CONNECTOR_H_
#define ST_ASIO_WRAPPER_CONNECTOR_H_

Y
youngwolf 已提交
16
#include "st_asio_wrapper_tcp_socket.h"
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

#ifndef SERVER_IP
#define SERVER_IP				"127.0.0.1"
#endif
#ifndef SERVER_PORT
#define SERVER_PORT				5050
#endif
#ifndef RE_CONNECT_INTERVAL
#define RE_CONNECT_INTERVAL		500 //millisecond(s)
#endif

#ifdef RE_CONNECT_CONTROL
#define RE_CONNECT_CHECK	prepare_re_connect()
#else
#define RE_CONNECT_CHECK	true
#endif

namespace st_asio_wrapper
{

37
template <typename MsgType = std::string, typename Socket = boost::asio::ip::tcp::socket, typename Packer = DEFAULT_PACKER, typename Unpacker = DEFAULT_UNPACKER>
38
class st_connector_base : public st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>
39 40
{
public:
41
	st_connector_base(boost::asio::io_service& io_service_) : st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>(io_service_), connected(false), reconnecting(true)
42 43 44 45 46
#ifdef RE_CONNECT_CONTROL
		, re_connect_times(-1)
#endif
		{set_server_addr(SERVER_PORT, SERVER_IP);}

Y
youngwolf 已提交
47
	template<typename Arg>
48
	st_connector_base(boost::asio::io_service& io_service_, Arg& arg) : st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>(io_service_, arg), connected(false), reconnecting(true)
Y
youngwolf 已提交
49 50 51 52 53 54
#ifdef RE_CONNECT_CONTROL
		, re_connect_times(-1)
#endif
		{set_server_addr(SERVER_PORT, SERVER_IP);}

	//reset all, be ensure that there's no any operations performed on this st_connector_base when invoke it
Y
youngowlf 已提交
55 56
	//notice, when reusing this st_connector_base, st_object_pool will invoke reset(), child must re-write this to initialize
	//all member variables, and then do not forget to invoke st_connector_base::reset() to initialize father's
57
	//member variables
58
	virtual void reset() {connected = false; reconnecting = true; st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>::reset();}
59

60
	bool set_server_addr(unsigned short port, const std::string& ip = SERVER_IP)
61
	{
Y
youngwolf 已提交
62
		boost::system::error_code ec;
63 64 65 66 67 68
		auto addr = boost::asio::ip::address::from_string(ip, ec);
		if (ec)
			return false;

		server_addr = boost::asio::ip::tcp::endpoint(addr, port);
		return true;
69
	}
Y
youngwolf 已提交
70
	const boost::asio::ip::tcp::endpoint& get_server_addr() const {return server_addr;}
71

72 73 74 75 76
#ifdef RE_CONNECT_CONTROL
	void set_re_connect_times(size_t times) {re_connect_times = times;}
#endif
	bool is_connected() const {return connected;}

Y
youngowlf 已提交
77
	//the following three functions can only be used when the connection is OK and you want to reconnect to the server.
78
	//if the connection is broken unexpectedly, st_connector will try to reconnect to the server automatically.
79
	void disconnect(bool reconnect = false) {force_close(reconnect);}
80
	void force_close(bool reconnect = false) {reconnecting = reconnect; connected = false; st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>::force_close();}
81
	void graceful_close(bool reconnect = false)
82 83
	{
		if (!is_connected())
84
			force_close(reconnect);
85 86
		else
		{
87
			reconnecting = reconnect;
88
			connected = false;
89
			st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>::graceful_close();
90 91 92 93
		}
	}

protected:
Y
youngowlf 已提交
94
	virtual bool do_start() //connect or receive
95
	{
Y
youngwolf 已提交
96
		if (!ST_THIS get_io_service().stopped())
97
		{
Y
Bug fix  
youngwolf 已提交
98
			if (reconnecting && !is_connected())
99
				ST_THIS lowest_layer().async_connect(server_addr, boost::bind(&st_connector_base::connect_handler, this, boost::asio::placeholders::error));
100
			else
Y
youngwolf 已提交
101
				ST_THIS do_recv_msg();
102 103 104 105 106 107 108

			return true;
		}

		return false;
	}

109
	virtual void on_connect() {unified_out::info_out("connecting success.");}
110
	virtual bool is_send_allowed() const {return is_connected() && st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>::is_send_allowed();}
111
	virtual void on_unpack_error() {unified_out::info_out("can not unpack msg."); force_close();}
Y
youngwolf 已提交
112
	virtual void on_recv_error(const boost::system::error_code& ec)
113 114 115
	{
		unified_out::error_out("connection closed.");

116
		auto reconnect = reconnecting;
Y
youngwolf 已提交
117
		if (ST_THIS is_closing())
118
			force_close(reconnecting);
119 120
		else
		{
121
			force_close(reconnecting);
Y
Bug fix  
youngwolf 已提交
122 123
			if (reconnect && (!ec || boost::asio::error::operation_aborted == ec || !RE_CONNECT_CHECK))
				reconnect = false;
124 125
		}

126
		if (reconnect)
127
			do_start();
128 129 130 131 132 133 134
	}

	virtual bool on_timer(unsigned char id, const void* user_data)
	{
		switch(id)
		{
		case 10:
135
			do_start();
136 137 138 139
			break;
		case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: //reserved
			break;
		default:
140
			return st_tcp_socket_base<MsgType, Socket, Packer, Unpacker>::on_timer(id, user_data);
141 142 143 144 145 146
			break;
		}

		return false;
	}

Y
youngwolf 已提交
147
	void connect_handler(const boost::system::error_code& ec)
148 149 150
	{
		if (!ec)
		{
Y
Bug fix  
youngwolf 已提交
151
			connected = reconnecting = true;
152
			on_connect();
Y
youngwolf 已提交
153
			ST_THIS send_msg(); //send msg buffer may have msgs, send them
154
			do_start();
155
		}
156
		else if ((boost::asio::error::operation_aborted != ec || reconnecting) && RE_CONNECT_CHECK && !ST_THIS get_io_service().stopped())
Y
youngwolf 已提交
157
			ST_THIS set_timer(10, RE_CONNECT_INTERVAL, nullptr);
158 159 160
	}

#ifdef RE_CONNECT_CONTROL
161 162 163 164 165 166 167 168 169 170 171
	bool prepare_re_connect()
	{
		if (0 == re_connect_times)
		{
			unified_out::info_out("re-connecting abandoned!");
			return false;
		}

		--re_connect_times;
		return true;
	}
172 173 174
#endif

protected:
Y
youngwolf 已提交
175
	boost::asio::ip::tcp::endpoint server_addr;
176
	bool connected;
177
	bool reconnecting;
178 179 180 181
#ifdef RE_CONNECT_CONTROL
	size_t re_connect_times;
#endif
};
Y
youngwolf 已提交
182
typedef st_connector_base<> st_connector;
183 184 185 186

} //namespace

#endif /* ST_ASIO_WRAPPER_CONNECTOR_H_ */