103 Star 821 Fork 259

GVPlibhv / libhv

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
tcp_client_test.c 6.94 KB
一键复制 编辑 原始数据 按行查看 历史
ithewei 提交于 2023-04-20 11:43 . fix #366: double kill reconn_timer
/*
* tcp client demo
*
* @build make examples
* @server bin/tcp_echo_server 1234
* @client bin/tcp_client_test 127.0.0.1 1234
*
*/
#include "hloop.h"
#include "hssl.h"
#include "hmutex.h"
#include "hbase.h"
#include "herr.h"
#define TEST_SSL 0
#define TEST_UNPACK 0
#define TEST_RECONNECT 1
// @see mqtt/mqtt_client.h
typedef struct tcp_client_s {
// connect: host:port
char host[256];
int port;
int connect_timeout; // ms
// reconnect
reconn_setting_t* reconn_setting;
// flags
unsigned char ssl: 1; // Read Only
unsigned char alloced_ssl_ctx: 1; // intern
unsigned char connected : 1;
// privdata
hloop_t* loop;
hio_t* io;
htimer_t* reconn_timer;
// SSL/TLS
hssl_ctx_t ssl_ctx;
// thread-safe
hmutex_t mutex_;
// ...
} tcp_client_t;
static tcp_client_t* tcp_client_new(hloop_t* loop DEFAULT(NULL));
static void tcp_client_run (tcp_client_t* cli);
static void tcp_client_stop(tcp_client_t* cli);
static void tcp_client_free(tcp_client_t* cli);
// SSL/TLS
static int tcp_client_set_ssl_ctx(tcp_client_t* cli, hssl_ctx_t ssl_ctx);
static int tcp_client_new_ssl_ctx(tcp_client_t* cli, hssl_ctx_opt_t* opt);
// reconnect
static int tcp_client_set_reconnect(tcp_client_t* cli, reconn_setting_t* reconn);
static int tcp_client_reconnect(tcp_client_t* cli);
static void tcp_client_set_connnect_timeout(tcp_client_t* cli, int timeout_ms);
static int tcp_client_connect(tcp_client_t* cli, const char* host, int port, int ssl);
static int tcp_client_disconnect(tcp_client_t* cli);
static bool tcp_client_is_connected(tcp_client_t* cli);
static int tcp_client_send(tcp_client_t* cli, const void* buf, int len);
static void reconnect_timer_cb(htimer_t* timer) {
tcp_client_t* cli = (tcp_client_t*)hevent_userdata(timer);
if (cli == NULL) return;
cli->reconn_timer = NULL;
tcp_client_reconnect(cli);
}
static void on_close(hio_t* io) {
printf("onclose: connfd=%d error=%d\n", hio_fd(io), hio_error(io));
tcp_client_t* cli = (tcp_client_t*)hevent_userdata(io);
cli->connected = 0;
// reconnect
if (cli->reconn_setting && reconn_setting_can_retry(cli->reconn_setting)) {
uint32_t delay = reconn_setting_calc_delay(cli->reconn_setting);
printf("reconnect cnt=%d, delay=%d ...\n", cli->reconn_setting->cur_retry_cnt, cli->reconn_setting->cur_delay);
cli->reconn_timer = htimer_add(cli->loop, reconnect_timer_cb, delay, 1);
hevent_set_userdata(cli->reconn_timer, cli);
}
}
static void on_message(hio_t* io, void* buf, int len) {
printf("onmessage: %.*s\n", len, (char*)buf);
tcp_client_t* cli = (tcp_client_t*)hevent_userdata(io);
// ...
}
static void on_connect(hio_t* io) {
printf("onconnect: connfd=%d\n", hio_fd(io));
tcp_client_t* cli = (tcp_client_t*)hevent_userdata(io);
cli->connected = 1;
#if TEST_UNPACK
static unpack_setting_t s_unpack_setting;
s_unpack_setting.mode = UNPACK_BY_DELIMITER;
s_unpack_setting.package_max_length = DEFAULT_PACKAGE_MAX_LENGTH;
s_unpack_setting.delimiter_bytes = 2;
s_unpack_setting.delimiter[0] = '\r';
s_unpack_setting.delimiter[1] = '\n';
hio_set_unpack(io, &s_unpack_setting);
#endif
hio_write(io, "hello\r\n", 7);
hio_setcb_read(io, on_message);
hio_read(io);
}
// hloop_new -> malloc(tcp_client_t)
tcp_client_t* tcp_client_new(hloop_t* loop) {
if (loop == NULL) {
loop = hloop_new(HLOOP_FLAG_AUTO_FREE);
if (loop == NULL) return NULL;
}
tcp_client_t* cli = NULL;
HV_ALLOC_SIZEOF(cli);
if (cli == NULL) return NULL;
cli->loop = loop;
hmutex_init(&cli->mutex_);
return cli;
}
// hloop_free -> free(tcp_client_t)
void tcp_client_free(tcp_client_t* cli) {
if (!cli) return;
hmutex_destroy(&cli->mutex_);
if (cli->ssl_ctx && cli->alloced_ssl_ctx) {
hssl_ctx_free(cli->ssl_ctx);
cli->ssl_ctx = NULL;
}
HV_FREE(cli->reconn_setting);
HV_FREE(cli);
}
void tcp_client_run (tcp_client_t* cli) {
if (!cli || !cli->loop) return;
hloop_run(cli->loop);
}
void tcp_client_stop(tcp_client_t* cli) {
if (!cli || !cli->loop) return;
hloop_stop(cli->loop);
}
int tcp_client_set_ssl_ctx(tcp_client_t* cli, hssl_ctx_t ssl_ctx) {
cli->ssl_ctx = ssl_ctx;
return 0;
}
// hssl_ctx_new(opt) -> tcp_client_set_ssl_ctx
int tcp_client_new_ssl_ctx(tcp_client_t* cli, hssl_ctx_opt_t* opt) {
opt->endpoint = HSSL_CLIENT;
hssl_ctx_t ssl_ctx = hssl_ctx_new(opt);
if (ssl_ctx == NULL) return ERR_NEW_SSL_CTX;
cli->alloced_ssl_ctx = true;
return tcp_client_set_ssl_ctx(cli, ssl_ctx);
}
int tcp_client_set_reconnect(tcp_client_t* cli, reconn_setting_t* reconn) {
if (reconn == NULL) {
HV_FREE(cli->reconn_setting);
return 0;
}
if (cli->reconn_setting == NULL) {
HV_ALLOC_SIZEOF(cli->reconn_setting);
}
*cli->reconn_setting = *reconn;
return 0;
}
int tcp_client_reconnect(tcp_client_t* cli) {
tcp_client_connect(cli, cli->host, cli->port, cli->ssl);
return 0;
}
int tcp_client_connect(tcp_client_t* cli, const char* host, int port, int ssl) {
if (!cli) return -1;
hv_strncpy(cli->host, host, sizeof(cli->host));
cli->port = port;
cli->ssl = ssl;
hio_t* io = hio_create_socket(cli->loop, host, port, HIO_TYPE_TCP, HIO_CLIENT_SIDE);
if (io == NULL) return -1;
if (ssl) {
if (cli->ssl_ctx) {
hio_set_ssl_ctx(io, cli->ssl_ctx);
}
hio_enable_ssl(io);
}
if (cli->connect_timeout > 0) {
hio_set_connect_timeout(io, cli->connect_timeout);
}
cli->io = io;
hevent_set_userdata(io, cli);
hio_setcb_connect(io, on_connect);
hio_setcb_close(io, on_close);
return hio_connect(io);
}
int tcp_client_disconnect(tcp_client_t* cli) {
if (!cli || !cli->io) return -1;
// cancel reconnect first
tcp_client_set_reconnect(cli, NULL);
return hio_close(cli->io);
}
bool tcp_client_is_connected(tcp_client_t* cli) {
return cli && cli->connected;
}
int tcp_client_send(tcp_client_t* cli, const void* buf, int len) {
if (!cli || !cli->io || !buf || len == 0) return -1;
if (!cli->connected) return -2;
// thread-safe
hmutex_lock(&cli->mutex_);
int nwrite = hio_write(cli->io, buf, len);
hmutex_unlock(&cli->mutex_);
return nwrite;
}
int main(int argc, char** argv) {
if (argc < 3) {
printf("Usage: %s host port\n", argv[0]);
return -10;
}
const char* host = argv[1];
int port = atoi(argv[2]);
tcp_client_t* cli = tcp_client_new(NULL);
if (!cli) return -20;
#if TEST_RECONNECT
reconn_setting_t reconn;
reconn_setting_init(&reconn);
reconn.min_delay = 1000;
reconn.max_delay = 10000;
reconn.delay_policy = 2;
tcp_client_set_reconnect(cli, &reconn);
#endif
int ssl = 0;
#if TEST_SSL
ssl = 1;
#endif
tcp_client_connect(cli, host, port, ssl);
tcp_client_run(cli);
tcp_client_free(cli);
return 0;
}
C++
1
https://gitee.com/libhv/libhv.git
git@gitee.com:libhv/libhv.git
libhv
libhv
libhv
master

搜索帮助