From 9a60841a40b2e6cd7f64456a1d7b7a132253447d Mon Sep 17 00:00:00 2001 From: Gregory Gauthier Date: Thu, 26 Mar 2026 16:21:30 +0000 Subject: [PATCH] add udp client --- src/c90/perf_client_udp.c | 157 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/c90/perf_client_udp.c diff --git a/src/c90/perf_client_udp.c b/src/c90/perf_client_udp.c new file mode 100644 index 0000000..e245cb0 --- /dev/null +++ b/src/c90/perf_client_udp.c @@ -0,0 +1,157 @@ +/* perf_client_udp.c - STRICT C89/C90 UDP performance tester for the metric protocol */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 9999 +#define BUF_SIZE 1024 +#define TEST_DURATION 30 /* seconds */ + +#define MSG_PING 0x01 +#define MSG_PONG 0x02 +#define MSG_METRIC_REQ 0x03 +#define MSG_METRIC_RESP 0x04 +#define MSG_SUBSCRIBE 0x05 +#define MSG_PUSH 0x06 +#define MSG_UNSUB 0x07 +#define MSG_ERROR 0xFF + +#define HEADER_SIZE 3 + +static void send_to(int sock, struct sockaddr_in *to, + unsigned char type, const void *payload, unsigned short len) +{ + unsigned char header[HEADER_SIZE]; + header[0] = type; + header[1] = (len >> 8) & 0xFF; + header[2] = len & 0xFF; + sendto(sock, header, HEADER_SIZE, 0, (struct sockaddr *)to, sizeof(*to)); + if (len > 0) + sendto(sock, payload, len, 0, (struct sockaddr *)to, sizeof(*to)); +} + +static int recv_from_exact(int sock, void *buf, int n) +{ + int total = 0; + while (total < n) { + int r = recv(sock, (char *)buf + total, n - total, 0); + if (r <= 0) return -1; + total += r; + } + return total; +} + +int main(int argc, char *argv[]) +{ + int sock, maxfd, flood_mode = 0, duration = TEST_DURATION; + struct sockaddr_in server_addr; + unsigned char header[HEADER_SIZE]; + unsigned char payload[BUF_SIZE]; + double val; + unsigned char type; + unsigned short len; + fd_set readfds; + time_t start, now; + unsigned long count = 0; + const char *metric = "cpu"; + unsigned int interval_ms = 10; /* 10 ms pushes in subscribe mode */ + + if (argc > 1 && strcmp(argv[1], "--flood") == 0) flood_mode = 1; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { perror("socket"); exit(1); } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); + + printf("=== UDP Metric Performance Test (C89) ===\n"); + printf("Server: 127.0.0.1:%d\n", PORT); + if (flood_mode) { + printf("Mode: FLOOD (rapid get %s)\n", metric); + } else { + printf("Mode: SUBSCRIBE '%s' every %u ms\n", metric, interval_ms); + } + printf("Test duration: %d seconds\n\n", duration); + + /* Subscribe or start flooding */ + if (flood_mode) { + /* nothing extra needed */ + } else { + unsigned char p[BUF_SIZE]; + unsigned char name_len = strlen(metric); + p[0] = name_len; + memcpy(p + 1, metric, name_len); + p[1 + name_len] = (interval_ms >> 24) & 0xFF; + p[1 + name_len + 1] = (interval_ms >> 16) & 0xFF; + p[1 + name_len + 2] = (interval_ms >> 8) & 0xFF; + p[1 + name_len + 3] = interval_ms & 0xFF; + send_to(sock, &server_addr, MSG_SUBSCRIBE, p, 1 + name_len + 4); + printf("Subscribed... counting PUSHes\n"); + } + + start = time(NULL); + maxfd = sock + 1; + + while (1) { + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + + if (select(maxfd, &readfds, NULL, NULL, NULL) < 0) { + if (errno == EINTR) continue; + perror("select"); + break; + } + + if (FD_ISSET(sock, &readfds)) { + if (recv_from_exact(sock, header, HEADER_SIZE) != HEADER_SIZE) break; + + type = header[0]; + len = (header[1] << 8) | header[2]; + + if (len > 0) { + if (recv_from_exact(sock, payload, len) != len) break; + } + + if (type == MSG_PUSH) { + unsigned char name_len = payload[0]; + payload[1 + name_len] = '\0'; + memcpy(&val, payload + 1 + name_len, sizeof(double)); + count++; + } + else if (type == MSG_METRIC_RESP && flood_mode) { + count++; + } + else if (type == MSG_ERROR) { + printf(" [ERROR] %.*s\n", len, payload); + } + } + + now = time(NULL); + if (now - start >= duration) break; + } + + if (!flood_mode) { + send_to(sock, &server_addr, MSG_UNSUB, NULL, 0); + } + + printf("\n=== Results ===\n"); + printf("Duration: %lu seconds\n", (unsigned long)(now - start)); + printf("Messages received: %lu\n", count); + printf("Throughput: %.1f messages/second\n", (double)count / (now - start)); + if (flood_mode) { + printf("(This is the rate of successful round-trips)\n"); + } else { + printf("(UDP PUSH rate — best-effort)\n"); + } + + close(sock); + return 0; +}