Skip to content

Commit f69f39d

Browse files
committed
[Network/TcpServer] Made the TCP server run asynchronously
- Starting a server isn't blocking anymore and doesn't require an explicit thread to run asynchronously
1 parent ff1d627 commit f69f39d

File tree

5 files changed

+21
-21
lines changed

5 files changed

+21
-21
lines changed

examples/networkDemo.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ int main() {
77
Raz::Logger::setLoggingLevel(Raz::LoggingLevel::ALL);
88

99
Raz::TcpServer server;
10-
// The server runs synchronously; starting it in a separate thread to avoid blocking the main one
11-
std::thread([&server] () {
12-
Raz::Threading::setCurrentThreadName("Server thread");
13-
server.start(1234);
14-
}).detach();
10+
server.start(1234);
1511

1612
Raz::TcpClient client("localhost", 1234);
1713

include/RaZ/Network/TcpServer.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ class TcpServer {
1414
TcpServer(TcpServer&&) noexcept = default;
1515

1616
/// Starts the server and listens for connections.
17-
/// \note This operation is blocking; call the function from another thread if needed.
1817
/// \param port Port to listen for connections on.
1918
void start(unsigned short port);
2019
/// Stops the server.

src/RaZ/Network/TcpServer.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "RaZ/Network/TcpServer.hpp"
22
#include "RaZ/Utils/Logger.hpp"
3+
#include "RaZ/Utils/Threading.hpp"
34

45
#include "asio/ip/tcp.hpp"
56
#include "asio/write.hpp"
@@ -56,23 +57,32 @@ struct TcpServer::Impl {
5657

5758
asio::io_context context;
5859
asio::ip::tcp::acceptor acceptor;
60+
std::thread contextThread;
5961
};
6062

6163
TcpServer::TcpServer() : m_impl{ std::make_unique<Impl>() } {}
6264

6365
void TcpServer::start(unsigned short port) {
6466
Logger::debug("[TcpServer] Starting on port {}...", port);
6567

68+
stop();
6669
setup(port);
6770
accept();
6871

69-
m_impl->context.run();
72+
m_impl->contextThread = std::thread([this] () {
73+
Threading::setCurrentThreadName("TCP server");
74+
m_impl->context.run();
75+
});
7076
}
7177

7278
void TcpServer::stop() {
7379
Logger::debug("[TcpServer] Stopping...");
80+
7481
m_impl->acceptor.close();
7582
m_impl->context.stop();
83+
if (m_impl->contextThread.joinable())
84+
m_impl->contextThread.join();
85+
7686
Logger::debug("[TcpServer] Stopped");
7787
}
7888

tests/src/RaZ/Network/TcpClient.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ TEST_CASE("TcpClient connection", "[network]") {
2626

2727
CHECK_THROWS(client.connect("localhost", 1234)); // No server to connect to
2828

29-
std::thread serverThread([&server] () { server.start(1234); });
29+
server.start(1234);
3030

3131
CHECK_NOTHROW(client.connect("localhost", 1234));
3232
CHECK(client.isConnected());
@@ -35,12 +35,11 @@ TEST_CASE("TcpClient connection", "[network]") {
3535
CHECK_FALSE(client.isConnected());
3636

3737
CHECK_NOTHROW(server.stop());
38-
CHECK_NOTHROW(serverThread.join());
3938
}
4039

4140
TEST_CASE("TcpClient send and receive", "[network]") {
4241
Raz::TcpServer server;
43-
std::thread serverThread([&server] () { server.start(1234); });
42+
server.start(1234);
4443

4544
Raz::TcpClient client("localhost", 1234);
4645
REQUIRE(client.isConnected());
@@ -55,12 +54,11 @@ TEST_CASE("TcpClient send and receive", "[network]") {
5554

5655
client.disconnect();
5756
server.stop();
58-
serverThread.join();
5957
}
6058

6159
TEST_CASE("TcpClient receive at least", "[network]") {
6260
Raz::TcpServer server;
63-
std::thread serverThread([&server] () { server.start(1234); });
61+
server.start(1234);
6462

6563
Raz::TcpClient client("localhost", 1234);
6664
REQUIRE(client.isConnected());
@@ -74,12 +72,11 @@ TEST_CASE("TcpClient receive at least", "[network]") {
7472

7573
client.disconnect();
7674
server.stop();
77-
serverThread.join();
7875
}
7976

8077
TEST_CASE("TcpClient receive exactly", "[network]") {
8178
Raz::TcpServer server;
82-
std::thread serverThread([&server] () { server.start(1234); });
79+
server.start(1234);
8380

8481
Raz::TcpClient client("localhost", 1234);
8582
REQUIRE(client.isConnected());
@@ -90,12 +87,11 @@ TEST_CASE("TcpClient receive exactly", "[network]") {
9087

9188
client.disconnect();
9289
server.stop();
93-
serverThread.join();
9490
}
9591

9692
TEST_CASE("TcpClient receive until delimiter", "[network]") {
9793
Raz::TcpServer server;
98-
std::thread serverThread([&server] () { server.start(1234); });
94+
server.start(1234);
9995

10096
Raz::TcpClient client("localhost", 1234);
10197
REQUIRE(client.isConnected());
@@ -106,5 +102,4 @@ TEST_CASE("TcpClient receive until delimiter", "[network]") {
106102

107103
client.disconnect();
108104
server.stop();
109-
serverThread.join();
110105
}

tests/src/RaZ/Network/TcpServer.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ TEST_CASE("TcpServer basic", "[network]") {
99

1010
CHECK_NOTHROW(server.stop()); // Stopping a non-running server isn't an error
1111

12-
std::thread serverThread([&server] () { server.start(1234); });
13-
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Waiting for the server to start
12+
CHECK_NOTHROW(server.start(1234));
13+
CHECK_NOTHROW(server.start(1234)); // Starting an already running server restarts it properly
1414

15-
server.stop();
16-
serverThread.join();
15+
CHECK_NOTHROW(server.stop());
16+
CHECK_NOTHROW(server.stop()); // Stopping an already stopped server does nothing
1717
}

0 commit comments

Comments
 (0)