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 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <errno.h>
39#include <getopt.h>
40#include <signal.h>
41
42#include "nilorea/n_common.h"
43#include "nilorea/n_log.h"
44#include "nilorea/n_network.h"
47
49#define NETMSG_DATA 1
50
51static int client_echo_mode = 0;
52
54typedef struct CLIENT_STATE {
56 char* host;
58 char* port;
62 size_t fail_count;
64 pthread_mutex_t lock;
66
72static void* client_worker_fast(void* ptr) {
73 CLIENT_STATE* state = (CLIENT_STATE*)ptr;
74 __n_assert(state, return NULL);
75
76 NETWORK* netw = NULL;
77 if (netw_connect(&netw, state->host, state->port, NETWORK_IPALL) != TRUE) {
78 pthread_mutex_lock(&state->lock);
79 state->fail_count++;
80 pthread_mutex_unlock(&state->lock);
81 return NULL;
82 }
83
84 pthread_mutex_lock(&state->lock);
85 state->success_count++;
86 pthread_mutex_unlock(&state->lock);
87
89 return NULL;
90}
91
97static void* client_worker_echo(void* ptr) {
98 CLIENT_STATE* state = (CLIENT_STATE*)ptr;
99 __n_assert(state, return NULL);
100
101 NETWORK* netw = NULL;
102 if (netw_connect(&netw, state->host, state->port, NETWORK_IPALL) != TRUE) {
103 pthread_mutex_lock(&state->lock);
104 state->fail_count++;
105 pthread_mutex_unlock(&state->lock);
106 return NULL;
107 }
108
110
111 /* build and send a message */
112 NETW_MSG* msg = NULL;
113 create_msg(&msg);
114 if (msg) {
116 N_STR* payload = char_to_nstr("HELLO_FROM_CLIENT");
117 add_nstrptr_to_msg(msg, payload);
118 N_STR* packed = make_str_from_msg(msg);
119 delete_msg(&msg);
120 if (packed) {
121 netw_add_msg(netw, packed);
122 }
123 }
124
125 /* wait for echo response */
126 N_STR* response = netw_wait_msg(netw, 10000, 20000000);
127 if (response) {
128 free_nstr(&response);
129 pthread_mutex_lock(&state->lock);
130 state->success_count++;
131 pthread_mutex_unlock(&state->lock);
132 } else {
133 pthread_mutex_lock(&state->lock);
134 state->fail_count++;
135 pthread_mutex_unlock(&state->lock);
136 n_log(LOG_DEBUG, "no response from server");
137 }
138
140 return NULL;
141}
142
143static void usage(void) {
144 fprintf(stderr,
145 "Usage: ex_accept_pool_client [options]\n"
146 " -s HOST server address (required)\n"
147 " -p PORT server port (required)\n"
148 " -n COUNT number of connections (default: 500)\n"
149 " -t THREADS concurrent client threads (default: 8)\n"
150 " -e echo mode: send+recv messages (default: connect+close)\n"
151 " -V LEVEL log level (default: LOG_NOTICE)\n"
152 " -h show this help\n");
153}
154
155int main(int argc, char** argv) {
156 char* host = NULL;
157 char* port = NULL;
158 int total = 500;
159 int nb_threads = 8;
160 int log_level = LOG_NOTICE;
161 int opt;
162
163 while ((opt = getopt(argc, argv, "hes:p:n:t:V:")) != -1) {
164 switch (opt) {
165 case 's':
166 host = strdup(optarg);
167 break;
168 case 'p':
169 port = strdup(optarg);
170 break;
171 case 'n':
172 total = atoi(optarg);
173 break;
174 case 't':
175 nb_threads = atoi(optarg);
176 break;
177 case 'e':
179 break;
180 case 'V':
181 if (!strcmp(optarg, "LOG_DEBUG"))
183 else if (!strcmp(optarg, "LOG_INFO"))
185 else if (!strcmp(optarg, "LOG_NOTICE"))
187 else if (!strcmp(optarg, "LOG_ERR"))
189 break;
190 case 'h':
191 default:
192 usage();
193 exit(1);
194 }
195 }
196
197 if (!host || !port) {
198 fprintf(stderr, "Error: -s HOST and -p PORT are required\n");
199 usage();
200 exit(1);
201 }
202
204
205#ifdef __linux__
206 signal(SIGPIPE, SIG_IGN);
207#endif
208
209 CLIENT_STATE state;
210 state.host = host;
211 state.port = port;
212 state.success_count = 0;
213 state.fail_count = 0;
214 pthread_mutex_init(&state.lock, NULL);
215
216 THREAD_POOL* pool = new_thread_pool((size_t)nb_threads, (size_t)(total + 16));
217 if (!pool) {
218 n_log(LOG_ERR, "Failed to create thread pool");
219 exit(1);
220 }
221
222 void* (*worker_func)(void*) = client_echo_mode ? &client_worker_echo : &client_worker_fast;
223
224 n_log(LOG_NOTICE, "=== Starting %d connections to %s:%s (%d threads, %s mode) ===",
225 total, host, port, nb_threads,
226 client_echo_mode ? "echo" : "connect+close");
227
228 struct timespec t_start, t_end;
229 clock_gettime(CLOCK_MONOTONIC, &t_start);
230
231 for (int i = 0; i < total; i++) {
232 add_threaded_process(pool, worker_func, (void*)&state, NORMAL_PROC);
233 if ((i + 1) % 100 == 0) {
234 n_log(LOG_NOTICE, "submitted %d/%d connection tasks", i + 1, total);
235 }
236 }
237
238 n_log(LOG_NOTICE, "All tasks submitted, waiting for completion...");
240
241 clock_gettime(CLOCK_MONOTONIC, &t_end);
242 double elapsed = (double)(t_end.tv_sec - t_start.tv_sec) +
243 (double)(t_end.tv_nsec - t_start.tv_nsec) / 1e9;
244
245 n_log(LOG_NOTICE, "=== RESULTS ===");
246 n_log(LOG_NOTICE, "Total: %d, Success: %zu, Failed: %zu",
247 total, state.success_count, state.fail_count);
248 n_log(LOG_NOTICE, "Time: %.3f seconds (%.1f conn/sec)",
249 elapsed, (double)total / elapsed);
250
251 destroy_threaded_pool(&pool, 500000);
252 pthread_mutex_destroy(&state.lock);
253
254 FreeNoLog(host);
256
257 netw_unload();
258 return 0;
259}
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:60
static NETWORK_POOL * pool
NETWORK * netw
Network for server mode, accepting incomming.
Definition ex_network.c:39
char * port
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:272
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_DEBUG
debug-level messages
Definition n_log.h:84
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
#define LOG_INFO
informational
Definition n_log.h:82
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:203
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:255
A box including a string and his lenght.
Definition n_str.h:61
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:3569
int netw_start_thr_engine(NETWORK *netw)
Start the NETWORK netw Threaded Engine.
Definition n_network.c:3740
#define NETWORK_IPALL
Flag for auto detection by OS of ip version to use.
Definition n_network.h:48
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
Definition n_network.c:2662
N_STR * netw_wait_msg(NETWORK *netw, unsigned int refresh, size_t timeout)
Wait a message from aimed NETWORK.
Definition n_network.c:3688
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:2359
Structure of a NETWORK.
Definition n_network.h:309
#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.