acl/lib_fiber/samples/tcp_keeper/main.cpp

308 lines
6.3 KiB
C++

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
acl::atomic_long __count;
acl::atomic_long __hit;
static int __step = 10000;
static int __loop = 1;
static struct timeval __begin;
class fiber_client : public acl::fiber
{
public:
fiber_client(int& counter, acl::tcp_keeper& keeper,
const char* addr, int max)
: counter_(counter)
, keeper_(keeper)
, addr_(addr)
, max_(max) {}
~fiber_client(void) {}
private:
acl::socket_stream* peek(void)
{
#if 1
bool reused;
//acl_doze(5);
acl::socket_stream* conn = keeper_.peek(addr_, &reused);
if (reused) {
++__hit;
}
return conn;
#else
acl::socket_stream* conn = new acl::socket_stream;
if (conn->open(addr_, 10, 10) == false) {
printf("connect %s error %s\r\n",
addr_.c_str(), acl::last_serror());
delete conn;
return NULL;
}
return conn;
#endif
}
// @override
void run(void)
{
printf("fiber-%d running\r\n", acl::fiber::self());
for (int i = 0; i < max_; i++) {
struct timeval begin;
gettimeofday(&begin, NULL);
acl::socket_stream* conn = peek();
struct timeval end;
gettimeofday(&end, NULL);
double spent = acl::stamp_sub(end, begin);
if (spent >= 1000) {
printf("%s(%d): spent: %.2f ms\r\n",
__FILE__, __LINE__, spent);
}
if (conn == NULL) {
printf("peek connection error=%s\r\n",
acl::last_serror());
continue;
}
conn->set_tcp_solinger(true, 0);
doit(*conn);
delete conn;
}
if (--counter_ == 0) {
struct timeval end;
gettimeofday(&end, NULL);
double spent = acl::stamp_sub(end, __begin);
double speed = 1000 * __count / (spent >= 1 ? spent : 1);
double hit_ratio;
if (__count == 0) {
hit_ratio = 0.0;
} else {
hit_ratio = ((double) (__hit.value()) * 100)
/ (double) __count.value();
}
printf("hit=%lld, count=%lld\r\n", __hit.value(), __count.value());
printf("all fiber_client over! total count=%lld, "
"speed=%.2f, hit=%lld, hit_ratio=%.2f%%\r\n",
__count.value(), speed, __hit.value(), hit_ratio);
}
printf("counter=%d\r\n", counter_);
}
void doit(acl::socket_stream& conn)
{
const char s[] = "hello world!\r\n";
acl::string buf;
for (int i = 0; i < __loop; i++) {
#if 1
if (conn.write(s, sizeof(s) - 1) == -1) {
printf("write error %s\r\n", acl::last_serror());
break;
}
if (conn.gets(buf) == false) {
printf("gets error %s\r\n", acl::last_serror());
break;
}
#endif
++__count;
if (__count % __step == 0) {
char tmp[256];
snprintf(tmp, sizeof(tmp), "addr=%s, fiber-%d,"
" gets line=[%s], n=%lld",
conn.get_peer(true), acl::fiber::self(),
buf.c_str(), __count.value());
acl::meter_time(__FUNCTION__, __LINE__, tmp);
}
}
}
private:
int& counter_;
acl::tcp_keeper& keeper_;
acl::string addr_;
int max_;
};
class fiber_sleep : public acl::fiber
{
public:
fiber_sleep(void) {}
~fiber_sleep(void) {}
private:
// @override
void run(void)
{
while (true) {
sleep(1);
}
}
};
class thread_client : public acl::thread
{
public:
thread_client(acl::tcp_keeper& keeper, const char* addr,
int nfibers, int max)
: keeper_(keeper)
, addr_(addr)
, nfibers_(nfibers)
, max_(max) {}
~thread_client(void) {}
private:
// @over
void* run(void)
{
int counter = 0;
std::vector<acl::fiber*> fibers;
for (int i = 0; i < nfibers_; i++) {
counter++;
acl::fiber* fb = new fiber_client(counter, keeper_,
addr_, max_);
fibers.push_back(fb);
fb->start();
}
#if 0
acl::fiber* fb = new fiber_sleep;
fb->start();
#endif
acl::fiber::schedule();
for (std::vector<acl::fiber*>::iterator it = fibers.begin();
it != fibers.end(); ++it) {
delete *it;
}
return NULL;
}
private:
acl::tcp_keeper& keeper_;
acl::string addr_;
int nfibers_;
int max_;
};
static void usage(const char* procname)
{
printf("usage: %s -h [help]\r\n"
" -s server_addrs\r\n"
" -c fibers_count[default: 10]\r\n"
" -n max_loop[default: 10]\r\n"
" -r rtt_min[default: 0]\r\n"
" -C conn_max[default: 200]\r\n"
" -t conn_ttl[default: 10]\r\n"
" -i step[default: 10000]\r\n"
" -l loop for one connection[default: 1]\r\n"
, procname);
}
static void append_addrs(acl::string& buf, std::vector<acl::string>& addrs)
{
const std::vector<acl::string>& tokens = buf.split2(";, \r\r\n");
for (std::vector<acl::string>::const_iterator cit = tokens.begin();
cit != tokens.end(); ++cit) {
addrs.push_back(*cit);
}
}
int main(int argc, char *argv[])
{
int ch, n = 10, max = 10, rtt_min = 0, conn_max = 200, conn_ttl = 10;
acl::string addrs_buf("127.0.0.1:8001");
std::vector<acl::string> addrs;
acl::acl_cpp_init();
acl::log::stdout_open(true);
acl::fiber::stdout_open(true);
while ((ch = getopt(argc, argv, "hs:c:n:i:l:r:C:t:")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
return 0;
case 's':
addrs_buf = optarg;
append_addrs(addrs_buf, addrs);
addrs_buf.clear();
break;
case 'c':
n = atoi(optarg);
break;
case 'n':
max = atoi(optarg);
break;
case 'r':
rtt_min = atoi(optarg);
break;
case 'C':
conn_max = atoi(optarg);
break;
case 't':
conn_ttl = atoi(optarg);
break;
case 'i':
__step = atoi(optarg);
break;
case 'l':
__loop = atoi(optarg);
break;
default:
break;
}
}
if (!addrs_buf.empty()) {
append_addrs(addrs_buf, addrs);
}
acl::log::debug_init("all:2");
acl::tcp_keeper keeper;
keeper.set_rtt_min(rtt_min);
keeper.set_conn_timeout(10)
.set_rw_timeout(10)
.set_conn_min(10)
.set_conn_max(conn_max)
.set_conn_ttl(conn_ttl)
.set_pool_ttl(10);
keeper.start();
gettimeofday(&__begin, NULL);
std::vector<acl::thread*> threads;
for (std::vector<acl::string>::const_iterator cit = addrs.begin();
cit != addrs.end(); ++cit) {
acl::thread* thr = new thread_client(keeper, *cit, n, max);
thr->set_detachable(false);
threads.push_back(thr);
thr->start();
}
for (std::vector<acl::thread*>::iterator it = threads.begin();
it != threads.end(); ++it) {
(*it)->wait();
delete *it;
}
keeper.stop();
return 0;
}