-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtcp_socket.cpp
More file actions
136 lines (111 loc) · 4.54 KB
/
tcp_socket.cpp
File metadata and controls
136 lines (111 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// my tiny header only crossplatform library for working with ip sockets
#include "tcp_socket.h"
#include <thread>
#include <chrono>
#include <cstdio>
using namespace ipsockets;
#if true
// server and client work on IPv4 mode
static const ip_type_e ip_type = v4;
static const addr4_t ip_server = "127.0.0.1:2000";
static const addr4_t ip_client = "127.0.0.1:2000";
#else
// server and client work on IPv6 mode
static const ip_type_e ip_type = v6;
static const addr6_t ip_server = "[::1]:2000";
static const addr6_t ip_client = "[::1]:2000";
#endif
using tcp_server_t = tcp_socket_t<ip_type, socket_type_e::server>;
using tcp_client_t = tcp_socket_t<ip_type, socket_type_e::client>;
// Handles a single client connection.
// All accepted connections will be automatically closed when will be closed main server connection
// so this thread with this function also will be finish
void accepted_client_func (tcp_client_t accepted_client) {
while (true) {
char buf[1000];
int res = accepted_client.recv (buf, 1000);
if (res > 0) { // success
buf[res] = '\0'; // ensure null termination for safe printing
printf ("server for accepted connection received: %s\n", buf); // print received data
std::this_thread::sleep_for (std::chrono::seconds (1)); // simulate some processing delay
accepted_client.send ("answer\0", 7);
}
else if (res == ipsockets::error_timeout)
printf ("server for accepted connection: recv timeout\n");
else if (res == ipsockets::error_unreachable)
printf ("server for accepted connection: client unreachable\n");
else if (res == ipsockets::error_tcp_closed) {
printf ("server for accepted connection: client closed connection\n");
return;
}
}
printf ("shutdown server for accepted connection\n");
}
// Simple server loop accepting connections.
// Each connection is handled in a detached thread.
bool shutdown_server = false;
tcp_server_t server_sock (log_e::debug);
void server_func () {
uint32_t timeout_ms = 1000; // recv/send timeout in ms (SO_RCVTIMEO), also affects accept() timeout on Linux
int max_incoming_queue = 1000; // maximum number of pending connections in the listen queue
if (server_sock.open (ip_server, timeout_ms, max_incoming_queue) == ipsockets::no_error) {
addr_t<ip_type> accepted_client_addr;
while (shutdown_server == false) {
// accept() waiting new connections until server socket will be closed
tcp_client_t accepted_client = server_sock.accept (accepted_client_addr);
if (accepted_client.state == state_e::opened) {
// fire-and-forget thread for this connection
printf ("server: accept new connection\n");
std::thread accepted_thread = std::thread (accepted_client_func, std::move (accepted_client));
accepted_thread.detach();
}
else
printf ("server: accepting new connections timeout\n");
}
}
printf ("server shutdown\n");
}
// Simple client sending periodic requests.
void client_func () {
// small delay to let server start listening
std::this_thread::sleep_for (std::chrono::milliseconds (200));
tcp_client_t sock (log_e::debug);
uint32_t timeout_ms = 1000; // recv/send timeout in ms (SO_RCVTIMEO)
uint32_t connect_timeout_ms = 5000; // connect timeout in ms (max wait for TCP handshake to complete)
if (sock.open (ip_client, timeout_ms, connect_timeout_ms) == ipsockets::no_error) {
for (size_t i = 0; i < 5; i++) {
std::this_thread::sleep_for (std::chrono::seconds (4));
if (sock.send ("hello\0", 6) >= 0) {
printf ("client send 'hello\\0' success\n");
char buf[1000];
int res = sock.recv (buf, 1000);
if (res > 0) { // success
buf[res] = '\0';
printf ("client received: %s\n", buf);
}
else if (res == ipsockets::error_timeout)
printf ("client: send timeout\n");
else if (res == ipsockets::error_unreachable)
printf ("client: server unreachable\n");
else if (res == ipsockets::error_tcp_closed)
printf ("client: server closed connection\n");
}
}
}
printf ("client shutdown\n");
}
int main () {
// start server and client in parallel
std::thread server (server_func);
std::thread client (client_func);
// wait for client is finish
client.join ();
// wait for server is finish
shutdown_server = true;
server_sock.close();
server.join ();
// wait 1 sec for shutdown accepted connetions
std::this_thread::sleep_for (std::chrono::seconds (1));
printf ("demo app shutdown\n");
return 0;
}