Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_accept_pool_client.c

Client for accept pool testing: connects repeatedly to stress the server.

Client for accept pool testing: connects repeatedly to stress the server

Author
Castagnier Mickael
Version
1.0
Date
11/03/2026

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.

/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include "nilorea/n_log.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;
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);
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;
}
/* build and send a message */
NETW_MSG* msg = NULL;
create_msg(&msg);
if (msg) {
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");
}
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 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':
break;
case 'V':
if (!strcmp(optarg, "LOG_DEBUG"))
else if (!strcmp(optarg, "LOG_INFO"))
else if (!strcmp(optarg, "LOG_NOTICE"))
else if (!strcmp(optarg, "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);
}
#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...");
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);
pthread_mutex_destroy(&state.lock);
FreeNoLog(host);
netw_unload();
return 0;
}
static int client_echo_mode
#define NETMSG_DATA
type of data message
size_t success_count
atomic counter of successful connections
char * port
server port
pthread_mutex_t lock
mutex for counters
static void * client_worker_fast(void *ptr)
Fast mode: connect and immediately close (measures pure accept throughput)
static void * client_worker_echo(void *ptr)
Echo mode: connect, send a message, receive echo, close.
size_t fail_count
atomic counter of failed connections
char * host
server host
static void usage(void)
shared state for client threads
int main(void)
int log_level
Definition ex_fluid.c:61
static NETWORK_POOL * pool
NETWORK * netw
Network for server mode, accepting incomming.
Definition ex_network.c:38
char * port
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:271
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:278
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_DEBUG
debug-level messages
Definition n_log.h:83
#define LOG_ERR
error conditions
Definition n_log.h:75
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:120
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:79
#define LOG_INFO
informational
Definition n_log.h:81
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:201
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:254
A box including a string and his lenght.
Definition n_str.h:60
N_STR * make_str_from_msg(NETW_MSG *msg)
Make a single string of the message.
int add_nstrptr_to_msg(NETW_MSG *msg, N_STR *str)
Add a string to the string list in the message.
int create_msg(NETW_MSG **msg)
Create a NETW_MSG *object.
int add_int_to_msg(NETW_MSG *msg, int value)
Add an int to the int list int the message.
int delete_msg(NETW_MSG **msg)
Delete a NETW_MSG *object.
network message, array of char and int
int netw_add_msg(NETWORK *netw, N_STR *msg)
Add a message to send in aimed NETWORK.
Definition n_network.c:2914
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition n_network.c:3050
#define NETWORK_IPALL
Flag for auto detection by OS of ip version to use.
Definition n_network.h:47
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition n_network.c:2041
N_STR * netw_wait_msg(NETWORK *netw, unsigned int refresh, size_t timeout)
Wait a message from aimed NETWORK.
Definition n_network.c:2998
int netw_connect(NETWORK **netw, char *host, char *port, int ip_version)
Use this to connect a NETWORK to any listening one, unrestricted send/recv lists.
Definition n_network.c:1814
Structure of a NETWORK.
Definition n_network.h:258
#define NORMAL_PROC
processing mode for added func, synced start, can be queued
THREAD_POOL * new_thread_pool(size_t nbmaxthr, size_t nb_max_waiting)
Create a new pool of nbmaxthr threads.
int add_threaded_process(THREAD_POOL *thread_pool, void *(*func_ptr)(void *param), void *param, int mode)
add a function and params to a thread pool
int wait_for_threaded_pool(THREAD_POOL *thread_pool)
Wait for the thread pool to become idle (no active threads, empty waiting list), blocking without pol...
int destroy_threaded_pool(THREAD_POOL **pool, unsigned int delay)
delete a thread_pool, exit the threads and free the structs
Structure of a thread pool.
Common headers and low-level functions & define.
Generic log system.
Network Engine.
Network messages , serialization tools.
Thread pool declaration.