Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_accept_pool_client.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <errno.h>
38#include <getopt.h>
39#include <signal.h>
40
41#include "nilorea/n_common.h"
42#include "nilorea/n_log.h"
43#include "nilorea/n_network.h"
46
48#define NETMSG_DATA 1
49
50static int client_echo_mode = 0;
51
53typedef struct CLIENT_STATE {
55 char* host;
57 char* port;
61 size_t fail_count;
63 pthread_mutex_t lock;
65
71static void* client_worker_fast(void* ptr) {
72 CLIENT_STATE* state = (CLIENT_STATE*)ptr;
73 __n_assert(state, return NULL);
74
75 NETWORK* netw = NULL;
76 if (netw_connect(&netw, state->host, state->port, NETWORK_IPALL) != TRUE) {
77 pthread_mutex_lock(&state->lock);
78 state->fail_count++;
79 pthread_mutex_unlock(&state->lock);
80 return NULL;
81 }
82
83 pthread_mutex_lock(&state->lock);
84 state->success_count++;
85 pthread_mutex_unlock(&state->lock);
86
88 return NULL;
89}
90
96static void* client_worker_echo(void* ptr) {
97 CLIENT_STATE* state = (CLIENT_STATE*)ptr;
98 __n_assert(state, return NULL);
99
100 NETWORK* netw = NULL;
101 if (netw_connect(&netw, state->host, state->port, NETWORK_IPALL) != TRUE) {
102 pthread_mutex_lock(&state->lock);
103 state->fail_count++;
104 pthread_mutex_unlock(&state->lock);
105 return NULL;
106 }
107
109
110 /* build and send a message */
111 NETW_MSG* msg = NULL;
112 create_msg(&msg);
113 if (msg) {
115 N_STR* payload = char_to_nstr("HELLO_FROM_CLIENT");
116 add_nstrptr_to_msg(msg, payload);
117 N_STR* packed = make_str_from_msg(msg);
118 delete_msg(&msg);
119 if (packed) {
120 netw_add_msg(netw, packed);
121 }
122 }
123
124 /* wait for echo response */
125 N_STR* response = netw_wait_msg(netw, 10000, 20000000);
126 if (response) {
127 free_nstr(&response);
128 pthread_mutex_lock(&state->lock);
129 state->success_count++;
130 pthread_mutex_unlock(&state->lock);
131 } else {
132 pthread_mutex_lock(&state->lock);
133 state->fail_count++;
134 pthread_mutex_unlock(&state->lock);
135 n_log(LOG_DEBUG, "no response from server");
136 }
137
139 return NULL;
140}
141
142static void usage(void) {
143 fprintf(stderr,
144 "Usage: ex_accept_pool_client [options]\n"
145 " -s HOST server address (required)\n"
146 " -p PORT server port (required)\n"
147 " -n COUNT number of connections (default: 500)\n"
148 " -t THREADS concurrent client threads (default: 8)\n"
149 " -e echo mode: send+recv messages (default: connect+close)\n"
150 " -V LEVEL log level (default: LOG_NOTICE)\n"
151 " -h show this help\n");
152}
153
154int main(int argc, char** argv) {
155 char* host = NULL;
156 char* port = NULL;
157 int total = 500;
158 int nb_threads = 8;
159 int log_level = LOG_NOTICE;
160 int opt;
161
162 while ((opt = getopt(argc, argv, "hes:p:n:t:V:")) != -1) {
163 switch (opt) {
164 case 's':
165 host = strdup(optarg);
166 break;
167 case 'p':
168 port = strdup(optarg);
169 break;
170 case 'n':
171 total = atoi(optarg);
172 break;
173 case 't':
174 nb_threads = atoi(optarg);
175 break;
176 case 'e':
178 break;
179 case 'V':
180 if (!strcmp(optarg, "LOG_DEBUG"))
182 else if (!strcmp(optarg, "LOG_INFO"))
184 else if (!strcmp(optarg, "LOG_NOTICE"))
186 else if (!strcmp(optarg, "LOG_ERR"))
188 break;
189 case 'h':
190 default:
191 usage();
192 exit(1);
193 }
194 }
195
196 if (!host || !port) {
197 fprintf(stderr, "Error: -s HOST and -p PORT are required\n");
198 usage();
199 exit(1);
200 }
201
203
204#ifdef __linux__
205 signal(SIGPIPE, SIG_IGN);
206#endif
207
208 CLIENT_STATE state;
209 state.host = host;
210 state.port = port;
211 state.success_count = 0;
212 state.fail_count = 0;
213 pthread_mutex_init(&state.lock, NULL);
214
215 THREAD_POOL* pool = new_thread_pool((size_t)nb_threads, (size_t)(total + 16));
216 if (!pool) {
217 n_log(LOG_ERR, "Failed to create thread pool");
218 exit(1);
219 }
220
221 void* (*worker_func)(void*) = client_echo_mode ? &client_worker_echo : &client_worker_fast;
222
223 n_log(LOG_NOTICE, "=== Starting %d connections to %s:%s (%d threads, %s mode) ===",
224 total, host, port, nb_threads,
225 client_echo_mode ? "echo" : "connect+close");
226
227 struct timespec t_start, t_end;
228 clock_gettime(CLOCK_MONOTONIC, &t_start);
229
230 for (int i = 0; i < total; i++) {
231 add_threaded_process(pool, worker_func, (void*)&state, NORMAL_PROC);
232 if ((i + 1) % 100 == 0) {
233 n_log(LOG_NOTICE, "submitted %d/%d connection tasks", i + 1, total);
234 }
235 }
236
237 n_log(LOG_NOTICE, "All tasks submitted, waiting for completion...");
239
240 clock_gettime(CLOCK_MONOTONIC, &t_end);
241 double elapsed = (double)(t_end.tv_sec - t_start.tv_sec) +
242 (double)(t_end.tv_nsec - t_start.tv_nsec) / 1e9;
243
244 n_log(LOG_NOTICE, "=== RESULTS ===");
245 n_log(LOG_NOTICE, "Total: %d, Success: %zu, Failed: %zu",
246 total, state.success_count, state.fail_count);
247 n_log(LOG_NOTICE, "Time: %.3f seconds (%.1f conn/sec)",
248 elapsed, (double)total / elapsed);
249
250 destroy_threaded_pool(&pool, 500000);
251 pthread_mutex_destroy(&state.lock);
252
253 FreeNoLog(host);
255
256 netw_unload();
257 return 0;
258}
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.