1+
2+ #include " tcp_socket.h"
3+
4+ #include < thread>
5+ #include < chrono>
6+ #include < string>
7+ #include < sstream>
8+ #include < cstdio>
9+
10+ using namespace ipsockets ;
11+
12+ #if true
13+ // server and client work on IPv4 mode
14+ static const ip_type_e cfg_ip_type = v4;
15+ static const addr4_t cfg_server = " 127.0.0.1:3000" ;
16+ static const addr4_t cfg_client = " 127.0.0.1:3000" ;
17+ #else
18+ // server and client work on IPv6 mode
19+ static const ip_type_e cfg_ip_type = v6;
20+ static const addr6_t cfg_server = " [::1]:3000" ;
21+ static const addr6_t cfg_client = " [::1]:3000" ;
22+ #endif
23+
24+ using tcp_server_t = tcp_socket_t <cfg_ip_type, socket_type_e::server>;
25+ using tcp_client_t = tcp_socket_t <cfg_ip_type, socket_type_e::client>;
26+ using tcp_stream_client_t = tcp_stream_t <cfg_ip_type, socket_type_e::client>;
27+
28+ log_e socket_log_level = log_e::error;
29+
30+ // ============================================================
31+ // Example 1: Basic << and >> operators
32+ // ============================================================
33+ // Server reads lines, client sends lines using iostream operators.
34+ bool shutdown_server { false };
35+ tcp_server_t server_sock { socket_log_level };
36+
37+ void example_1_server () {
38+
39+ if (server_sock.open (cfg_server) != no_error)
40+ return ;
41+
42+ printf (" [server] listening on %s\n " , cfg_server.to_str ().c_str ());
43+
44+ while (!shutdown_server) {
45+
46+ addr_t <cfg_ip_type> client_addr;
47+ tcp_client_t accepted = server_sock.accept (client_addr);
48+
49+ if (accepted.state != state_e::state_opened)
50+ continue ;
51+
52+ printf (" [server] client connected: %s\n " , client_addr.to_str ().c_str ());
53+
54+ // Wrap accepted socket into a stream
55+ tcp_stream_client_t stream (std::move (accepted));
56+
57+ { // --- Example: read with >> operator ---
58+ std::string word;
59+ stream >> word;
60+ if (stream)
61+ printf (" [server] received word: '%s'\n " , word.c_str ());
62+ }
63+
64+ { // --- Example: read with std::getline ---
65+ std::string line;
66+ if (std::getline (stream, line))
67+ printf (" [server] received line: '%s'\n " , line.c_str ());
68+ }
69+
70+ { // --- Example: read number ---
71+ int number = 0 ;
72+ stream >> number;
73+ if (stream)
74+ printf (" [server] received number: %d\n " , number);
75+ }
76+
77+ { // consume trailing newline after number
78+ std::string rest;
79+ std::getline (stream, rest);
80+ }
81+
82+ { // --- Example: read multi-word line ---
83+ std::string line;
84+ if (std::getline (stream, line))
85+ printf (" [server] received full line: '%s'\n " , line.c_str ());
86+ }
87+
88+ // --- Example: send response using << ---
89+ stream << " RESPONSE OK" << std::endl;
90+ stream << " value=" << 42 << std::endl;
91+ stream << " pi=" << 3.14159 << std::endl;
92+
93+ printf (" [server] response sent, closing connection\n " );
94+ // stream destructor flushes and the socket closes
95+ }
96+
97+ printf (" [server] shutdown\n " );
98+ }
99+
100+ void example_1_client () {
101+
102+ // small delay to let server start
103+ std::this_thread::sleep_for (std::chrono::milliseconds (200 ));
104+
105+ tcp_client_t sock (socket_log_level);
106+
107+ if (sock.open (cfg_client) != no_error) {
108+ printf (" [client] failed to connect\n " );
109+ return ;
110+ }
111+
112+ // Wrap client socket into a stream
113+ tcp_stream_client_t stream (std::move (sock));
114+
115+ printf (" [client] connected to %s\n " , stream.remote_address ().to_str ().c_str ());
116+
117+ // --- Send data using << operator ---
118+ stream << " Hello" ; // Send a word (server reads with >>)
119+ stream << " world_from_stream!" << ' \n ' ; // Send rest of line (server reads with getline — reads until \n)
120+ stream << 12345 << ' \n ' ; // Send a number
121+ stream << " This is a multi-word message with spaces" << ' \n ' ; // Send a full line with spaces
122+ stream << std::flush; // Flush to make sure everything is sent
123+ printf (" [client] all data sent\n " );
124+
125+ { // --- Read response using >> and getline ---
126+ std::string line;
127+ while (std::getline (stream, line))
128+ printf (" [client] received: '%s'\n " , line.c_str ());
129+ }
130+
131+ printf (" [client] done\n " );
132+ }
133+
134+
135+
136+ // ============================================================
137+ // Example 2: Structured data exchange
138+ // ============================================================
139+ // Shows sending/receiving structured data through streams.
140+
141+ void example_2_server_handler (tcp_client_t accepted) {
142+ tcp_stream_client_t stream (std::move (accepted));
143+
144+ // Read a command in format: "CMD arg1 arg2"
145+ std::string cmd;
146+ double a = 0 , b = 0 ;
147+ stream >> cmd >> a >> b;
148+
149+ if (!stream) {
150+ printf (" [server2] failed to read command\n " );
151+ return ;
152+ }
153+
154+ printf (" [server2] command='%s' a=%.2f b=%.2f\n " , cmd.c_str (), a, b);
155+
156+ // Compute and send result
157+ double result = 0 ;
158+ if (cmd == " ADD" ) result = a + b;
159+ else if (cmd == " MUL" ) result = a * b;
160+ else if (cmd == " SUB" ) result = a - b;
161+ else {
162+ stream << " ERROR unknown command" << std::endl;
163+ return ;
164+ }
165+
166+ stream << " RESULT " << result << std::endl;
167+ printf (" [server2] sent result: %.2f\n " , result);
168+ }
169+
170+ void example_2_server () {
171+
172+ tcp_server_t server (socket_log_level);
173+ if (server.open ({cfg_client.ip , 3001 }) != no_error)
174+ return ;
175+
176+ printf (" [server2] listening for calculator requests\n " );
177+
178+ for (int i = 0 ; i < 3 ; i++) {
179+ addr_t <cfg_ip_type> client_addr;
180+ tcp_client_t accepted = server.accept (client_addr);
181+ if (accepted.state == state_e::state_opened)
182+ example_2_server_handler (std::move (accepted));
183+ }
184+
185+ printf (" [server2] shutdown\n " );
186+ }
187+
188+ void example_2_client () {
189+
190+ std::this_thread::sleep_for (std::chrono::milliseconds (200 ));
191+
192+ // Send three calculator requests
193+ struct { const char * cmd; double a; double b; } requests[] = {
194+ { " ADD" , 10.5 , 20.3 },
195+ { " MUL" , 3.0 , 7.0 },
196+ { " SUB" , 100.0 , 42.0 }
197+ };
198+
199+ for (int i = 0 ; i < 3 ; i++) {
200+ tcp_client_t sock (socket_log_level);
201+ if (sock.open ({cfg_client.ip , 3001 }) != no_error) {
202+ printf (" [client2] failed to connect\n " );
203+ continue ;
204+ }
205+
206+ tcp_stream_client_t stream (std::move (sock));
207+
208+ // Send: "CMD a b\n"
209+ stream << requests[i].cmd << ' ' << requests[i].a << ' ' << requests[i].b << std::endl;
210+
211+ // Read response line
212+ std::string line;
213+ if (std::getline (stream, line))
214+ printf (" [client2] %s %.1f %.1f -> %s\n " , requests[i].cmd , requests[i].a , requests[i].b , line.c_str ());
215+ }
216+
217+ printf (" [client2] done\n " );
218+ }
219+
220+
221+
222+
223+ // ============================================================
224+ // Example 3: Line-by-line chat
225+ // ============================================================
226+ // Server echoes every line back in uppercase.
227+
228+ void example_3_server_handler (tcp_client_t accepted) {
229+ tcp_stream_client_t stream (std::move (accepted));
230+
231+ std::string line;
232+ while (std::getline (stream, line)) {
233+ printf (" [echo-server] received: '%s'\n " , line.c_str ());
234+
235+ if (line == " QUIT" )
236+ break ;
237+
238+ // Convert to uppercase and echo back
239+ for (char & c : line)
240+ if (' a' <= c && c <= ' z' )
241+ c = c - ' a' + ' A' ;
242+
243+ stream << line << ' \n ' ;
244+ }
245+
246+ stream << std::flush;
247+ printf (" [echo-server] client disconnected\n " );
248+ }
249+
250+ void example_3_server () {
251+
252+ tcp_server_t server (socket_log_level);
253+ if (server.open ({cfg_client.ip , 3002 }) != no_error)
254+ return ;
255+
256+ printf (" [echo-server] listening\n " );
257+
258+ addr_t <cfg_ip_type> client_addr;
259+ tcp_client_t accepted = server.accept (client_addr);
260+ if (accepted.state == state_e::state_opened)
261+ example_3_server_handler (std::move (accepted));
262+
263+ printf (" [echo-server] shutdown\n " );
264+ }
265+
266+ void example_3_client () {
267+
268+ std::this_thread::sleep_for (std::chrono::milliseconds (200 ));
269+
270+ tcp_client_t sock (socket_log_level);
271+ if (sock.open ({cfg_client.ip , 3002 }) != no_error)
272+ return ;
273+
274+ tcp_stream_client_t stream (std::move (sock));
275+
276+ // Send several lines and read echoed responses
277+ const char * messages[] = { " hello world" , " ip-sockets-cpp-lite is great" , " testing 123" };
278+
279+ for (const char * msg : messages) {
280+ stream << msg << ' \n ' ;
281+ stream << std::flush; // ensure data is sent before reading response
282+
283+ std::string response;
284+ if (std::getline (stream, response))
285+ printf (" [echo-client] sent='%s' received='%s'\n " , msg, response.c_str ());
286+ }
287+
288+ // Send quit command
289+ stream << " QUIT" << std::endl;
290+
291+ printf (" [echo-client] done\n " );
292+ }
293+
294+
295+ // ============================================================
296+ // Main — run all examples sequentially
297+ // ============================================================
298+
299+ int main () {
300+
301+ printf (" ========================================\n " );
302+ printf (" Example 1: Basic iostream operators\n " );
303+ printf (" ========================================\n\n " );
304+
305+ {
306+ std::thread server (example_1_server);
307+ std::thread client (example_1_client);
308+
309+ client.join ();
310+
311+ shutdown_server = true ;
312+ server_sock.close ();
313+ server.join ();
314+ }
315+
316+ std::this_thread::sleep_for (std::chrono::milliseconds (500 ));
317+
318+ printf (" \n ========================================\n " );
319+ printf (" Example 2: Calculator (structured)\n " );
320+ printf (" ========================================\n\n " );
321+
322+ {
323+ std::thread server (example_2_server);
324+ std::thread client (example_2_client);
325+
326+ client.join ();
327+ server.join ();
328+ }
329+
330+ std::this_thread::sleep_for (std::chrono::milliseconds (500 ));
331+
332+ printf (" \n ========================================\n " );
333+ printf (" Example 3: Echo server (line-by-line)\n " );
334+ printf (" ========================================\n\n " );
335+
336+ {
337+ std::thread server (example_3_server);
338+ std::thread client (example_3_client);
339+
340+ client.join ();
341+ server.join ();
342+ }
343+
344+ printf (" \n ========================================\n " );
345+ printf (" All examples completed!\n " );
346+ printf (" ========================================\n " );
347+
348+ return 0 ;
349+ }
0 commit comments