5 ex_accept_pool_client_8c example
gullradriel edited this page 2026-10-09 00:51:57 +02:00

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_