@@ -0,0 +1,150 @@
1+#include <stdio.h>
2+#include <stdlib.h>
3+#include <sys/types.h>
4+#include <sys/socket.h>
5+#include <netdb.h>
6+#include <string.h>
7+#include <unistd.h>
8+#include <signal.h>
9+#include <errno.h>
10+#include <time.h>
11+#include <sys/time.h>
12+#include <math.h>
13+
14+// Note: this is not consistent across CPUs (and hence across threads on multicore machines)
15+double timestamp() {
16+ struct timeval tp;
17+ gettimeofday(&tp, NULL);
18+ return ((double) tp.tv_sec) * 1e6 + (double) tp.tv_usec;
19+}
20+
21+int server() {
22+ printf("starting server\n");
23+
24+ struct addrinfo hints, *res;
25+ int error, server_socket;
26+
27+ memset(&hints, 0, sizeof(hints));
28+ hints.ai_family = PF_INET;
29+ hints.ai_socktype = SOCK_STREAM;
30+ hints.ai_flags = AI_PASSIVE;
31+
32+ error = getaddrinfo(NULL, "8080", &hints, &res);
33+ if(error) {
34+ printf("server error: %s\n", gai_strerror(error));
35+ return -1;
36+ }
37+
38+ server_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
39+ if(server_socket < 0) {
40+ printf("server error: could not create socket\n");
41+ return -1;
42+ }
43+
44+ int yes = 1;
45+ if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
46+ printf("server error: could not set socket options\n");
47+ return -1;
48+ }
49+
50+ if(bind(server_socket, res->ai_addr, res->ai_addrlen) < 0) {
51+ printf("server error: could not bind to socket\n");
52+ return -1;
53+ }
54+
55+ listen(server_socket, 5);
56+
57+ int client_socket;
58+ struct sockaddr_storage client_addr;
59+ socklen_t addr_size;
60+ client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &addr_size);
61+
62+ for(;;) {
63+ char* buf = malloc(8);
64+ ssize_t read = recv(client_socket, buf, 8, 0);
65+ if(read == 0) {
66+ free(buf);
67+ break;
68+ }
69+ // printf("server received '%s'\n", buf);
70+ send(client_socket, buf, 8, 0);
71+ free(buf);
72+ }
73+
74+ freeaddrinfo(res);
75+ return 0;
76+}
77+
78+int client(int pings) {
79+ printf("starting client\n");
80+
81+ struct addrinfo hints, *res;
82+ int error, client_socket;
83+
84+ memset(&hints, 0, sizeof(hints));
85+ hints.ai_family = PF_INET;
86+ hints.ai_socktype = SOCK_STREAM;
87+
88+ error = getaddrinfo("127.0.0.1", "8080", &hints, &res);
89+ if(error) {
90+ printf("client error: %s\n", gai_strerror(error));
91+ return -1;
92+ }
93+
94+ client_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
95+ if(client_socket < 0) {
96+ printf("client error: could not create socket\n");
97+ return -1;
98+ }
99+
100+ if(connect(client_socket, res->ai_addr, res->ai_addrlen) < 0) {
101+ printf("client error: could not connect: %s\n", strerror(errno));
102+ return -1;
103+ }
104+
105+ for(int i = 0; i < pings; i++) {
106+ double timestamp_before = timestamp();
107+
108+ send(client_socket, "ping123", 8, 0);
109+
110+ char *buf = malloc(8);
111+ ssize_t read = recv(client_socket, buf, 8, 0);
112+
113+ if(read == 0) {
114+ printf("server exited prematurely\n");
115+ free(buf);
116+ break;
117+ }
118+
119+ // printf("client received '%s'\n", buf);
120+ free(buf);
121+
122+ double timestamp_after = timestamp();
123+ fprintf(stderr, "%i %lf\n", i, timestamp_after - timestamp_before);
124+ }
125+
126+ printf("client did %d pings\n", pings);
127+
128+ freeaddrinfo(res);
129+ return 0;
130+}
131+
132+int usage(int argc, char** argv) {
133+ printf("usage: %s <number of pings>\n", argv[0]);
134+ return -1;
135+}
136+
137+int main(int argc, char** argv) {
138+ if(argc != 2) {
139+ return usage(argc, argv);
140+ }
141+
142+ if(fork() == 0) {
143+ // TODO: we should wait until we know the server is ready
144+ int pings = 0;
145+ sscanf(argv[1], "%d", &pings);
146+ return client(pings);
147+ } else {
148+ return server();
149+ }
150+}