Table of Contents
ex_accept_pool_client.c
Client for accept pool testing: connects repeatedly to stress the server Usage: ./ex_accept_pool_client -s HOST -p PORT -n 500 -t 8 ./ex_accept_pool_client -s HOST -p PORT -n 500 -t 8 -e (echo mode)
Default mode: connect + close (measures pure accept throughput). With -e: connect, send message, wait for echo, close. ```c
/*
- Nilorea Library
- Copyright (C) 2005-2026 Castagnier Mickael
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied. See the License for the specific language governing
- permissions and limitations under the License.
- SPDX-License-Identifier: Apache-2.0 */
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <getopt.h> #include <signal.h>
#include "nilorea/n_common.h" #include "nilorea/n_log.h" #include "nilorea/n_network.h" #include "nilorea/n_network_msg.h" #include "nilorea/n_thread_pool.h"
#define NETMSG_DATA 1
static int client_echo_mode = 0;
typedef struct CLIENT_STATE { char* host; char* port; size_t success_count; size_t fail_count; pthread_mutex_t lock; } CLIENT_STATE;
static void* client_worker_fast(void* ptr) { CLIENT_STATE* state = (CLIENT_STATE*)ptr; __n_assert(state, return NULL);
NETWORK* netw = NULL;
if (netw_connect(&netw, state->host, state->port, NETWORK_IPALL) != TRUE) {
pthread_mutex_lock(&state->lock);
state->fail_count++;
pthread_mutex_unlock(&state->lock);
return NULL;
}
pthread_mutex_lock(&state->lock);
state->success_count++;
pthread_mutex_unlock(&state->lock);
netw_close(&netw);
return NULL;
}
static void* client_worker_echo(void* ptr) { CLIENT_STATE* state = (CLIENT_STATE*)ptr; __n_assert(state, return NULL);
NETWORK* netw = NULL;
if (netw_connect(&netw, state->host, state->port, NETWORK_IPALL) != TRUE) {
pthread_mutex_lock(&state->lock);
state->fail_count++;
pthread_mutex_unlock(&state->lock);
return NULL;
}
netw_start_thr_engine(netw);
/* build and send a message */
NETW_MSG* msg = NULL;
create_msg(&msg);
if (msg) {
add_int_to_msg(msg, NETMSG_DATA);
N_STR* payload = char_to_nstr("HELLO_FROM_CLIENT");
add_nstrptr_to_msg(msg, payload);
N_STR* packed = make_str_from_msg(msg);
delete_msg(&msg);
if (packed) {
netw_add_msg(netw, packed);
}
}
/* wait for echo response */
N_STR* response = netw_wait_msg(netw, 10000, 20000000);
if (response) {
free_nstr(&response);
pthread_mutex_lock(&state->lock);
state->success_count++;
pthread_mutex_unlock(&state->lock);
} else {
pthread_mutex_lock(&state->lock);
state->fail_count++;
pthread_mutex_unlock(&state->lock);
n_log(LOG_DEBUG, "no response from server");
}
netw_close(&netw);
return NULL;
}
static void usage(void) { fprintf(stderr, "Usage: ex_accept_pool_client [options]\n" " -s HOST server address (required)\n" " -p PORT server port (required)\n" " -n COUNT number of connections (default: 500)\n" " -t THREADS concurrent client threads (default: 8)\n" " -e echo mode: send+recv messages (default: connect+close)\n" " -V LEVEL log level (default: LOG_NOTICE)\n" " -h show this help\n"); }
int main(int argc, char** argv) { char* host = NULL; char* port = NULL; int total = 500; int nb_threads = 8; int log_level = LOG_NOTICE; int opt;
while ((opt = getopt(argc, argv, "hes:p:n:t:V:")) != -1) {
switch (opt) {
case 's':
host = strdup(optarg);
break;
case 'p':
port = strdup(optarg);
break;
case 'n':
total = atoi(optarg);
break;
case 't':
nb_threads = atoi(optarg);
break;
case 'e':
client_echo_mode = 1;
break;
case 'V':
if (!strcmp(optarg, "LOG_DEBUG"))
log_level = LOG_DEBUG;
else if (!strcmp(optarg, "LOG_INFO"))
log_level = LOG_INFO;
else if (!strcmp(optarg, "LOG_NOTICE"))
log_level = LOG_NOTICE;
else if (!strcmp(optarg, "LOG_ERR"))
log_level = LOG_ERR;
break;
case 'h':
default:
usage();
exit(1);
}
}
if (!host || !port) {
fprintf(stderr, "Error: -s HOST and -p PORT are required\n");
usage();
exit(1);
}
set_log_level(log_level);
#ifdef linux signal(SIGPIPE, SIG_IGN); #endif
CLIENT_STATE state;
state.host = host;
state.port = port;
state.success_count = 0;
state.fail_count = 0;
pthread_mutex_init(&state.lock, NULL);
THREAD_POOL* pool = new_thread_pool((size_t)nb_threads, (size_t)(total + 16));
if (!pool) {
n_log(LOG_ERR, "Failed to create thread pool");
exit(1);
}
void* (*worker_func)(void*) = client_echo_mode ? &client_worker_echo : &client_worker_fast;
n_log(LOG_NOTICE, "=== Starting %d connections to %s:%s (%d threads, %s mode) ===",
total, host, port, nb_threads,
client_echo_mode ? "echo" : "connect+close");
struct timespec t_start, t_end;
clock_gettime(CLOCK_MONOTONIC, &t_start);
for (int i = 0; i < total; i++) {
add_threaded_process(pool, worker_func, (void*)&state, NORMAL_PROC);
if ((i + 1) % 100 == 0) {
n_log(LOG_NOTICE, "submitted %d/%d connection tasks", i + 1, total);
}
}
n_log(LOG_NOTICE, "All tasks submitted, waiting for completion...");
wait_for_threaded_pool(pool);
clock_gettime(CLOCK_MONOTONIC, &t_end);
double elapsed = (double)(t_end.tv_sec - t_start.tv_sec) +
(double)(t_end.tv_nsec - t_start.tv_nsec) / 1e9;
n_log(LOG_NOTICE, "=== RESULTS ===");
n_log(LOG_NOTICE, "Total: %d, Success: %zu, Failed: %zu",
total, state.success_count, state.fail_count);
n_log(LOG_NOTICE, "Time: %.3f seconds (%.1f conn/sec)",
elapsed, (double)total / elapsed);
destroy_threaded_pool(&pool, 500000);
pthread_mutex_destroy(&state.lock);
FreeNoLog(host);
FreeNoLog(port);
netw_unload();
return 0;
}
_Filename: ex_accept_pool_client.c_
Modules
- AABB3D
- ACCEPT_POOL
- ALLEGRO4
- ALLEGRO5
- ANIM_LIB
- ASTAR
- ATLAS_LIB
- AVRO
- CLOCK_SYNC
- COMMONS
- CONFIGFILE
- CYPHER_BASE64
- CYPHER_VIGENERE
- DEAD_RECKONING
- ENUMS
- EXCEPTIONS
- GAME_ENV
- GIT
- GUI
- HASH_TABLE
- ISOMETRIC_ENGINE
- LIST
- LOG
- LOGNODUP
- LZ4
- NETWORKING
- NETWORK_MSG
- N_COOKIES
- N_DIFF
- N_DIGEST
- N_DISK_CACHE
- N_DNS
- N_ECC
- N_ENTROPY
- N_FILES
- N_FLUIDS
- N_GUI_COLOR
- N_GUI_COLORWHEEL
- N_GUI_CURVE
- N_GUI_GRID
- N_GUI_POPUP
- N_HEX
- N_HTTP3
- N_HTTP_COOKIE
- N_HTTP_FORM
- N_HTTP_MIME
- N_HTTP_REQ
- N_HTTP_RESP
- N_HTTP_ROUTER
- N_HTTP_SERVER
- N_ICC
- N_JSON
- N_KAFKA
- N_LINALG
- N_MODULE
- N_OPENSSL_COMPAT
- N_PRETTY
- N_PTH
- N_QUERY
- N_RANDOM
- N_SHA256
- N_STR
- N_TIFF
- N_TIME
- N_USER
- N_X509
- N_ZIP
- PARTICLES
- PCRE
- PHYSICS
- SIGNALS
- STACK
- THREADS
- TRAJECTORY
- TREE
- ZLIB