read the source · systems/04_tcp_nodelay.c
#include "../tools/bench.h"
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#define REQS 500
static ssize_t read_n(int fd, char *b, size_t n) { size_t got = 0; while (got < n) { ssize_t r = read(fd, b + got, n - got); if (r <= 0) return r; got += (size_t)r; } return (ssize_t)got; }
static void *server(void *arg) {
bench_pin(4);
int ls = socket(AF_INET, SOCK_STREAM, 0), one = 1; setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
struct sockaddr_in a = { .sin_family = AF_INET, .sin_port = htons(40003), .sin_addr.s_addr = htonl(INADDR_LOOPBACK) };
bind(ls, (struct sockaddr *)&a, sizeof a); listen(ls, 1);
int fd = accept(ls, NULL, NULL); char buf[16];
for (int i = 0; i < REQS; i++) { if (read_n(fd, buf, 16) <= 0) break; (void)!write(fd, buf, 16); } /* 16-byte request -> 16-byte reply */
close(fd); close(ls); (void)arg; return NULL;
}
int main(int argc, char **argv) {
int nodelay = argc > 1 && !strcmp(argv[1], "nodelay");
pthread_t th; pthread_create(&th, NULL, server, NULL); usleep(20000);
bench_pin(2);
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in a = { .sin_family = AF_INET, .sin_port = htons(40003), .sin_addr.s_addr = htonl(INADDR_LOOPBACK) };
if (connect(fd, (struct sockaddr *)&a, sizeof a)) { perror("connect"); return 1; }
if (nodelay) { int one = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof one); }
uint64_t *s = malloc(REQS * sizeof *s); char hdr[4] = "HDR!", body[12] = "0123456789ab", reply[16];
for (int i = 0; i < REQS; i++) {
uint64_t t0 = bench_ns();
(void)!write(fd, hdr, 4); (void)!write(fd, body, 12); /* the classic write-write-read pattern */
read_n(fd, reply, 16);
s[i] = bench_ns() - t0;
}
pthread_join(th, NULL);
bench_stats st = bench_compute(s, REQS);
bench_print_header("request ns"); bench_print(nodelay ? "TCP_NODELAY" : "default (Nagle)", &st);
long slow = 0; for (int i = 0; i < REQS; i++) slow += s[i] > 1000000; printf("requests slower than 1 ms: %ld of %d\n", slow, REQS);
return 0;
}