Skip to content

Commit e2b4354

Browse files
merge: dev into master
Feature : complete abstraction of client and server classes for TCP/UDP
2 parents 0181c63 + 4a6e8d7 commit e2b4354

52 files changed

Lines changed: 1398 additions & 897 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ if (NOT TARGET PolymorphNetwork)
2626
if(WIN32)
2727
# MSVC
2828
# /wd4100: unreferenced formal parameter (= unused parameter)
29-
target_compile_options(PolymorphNetwork PRIVATE /W4)
29+
# /wd4250 : inherits via dominance
30+
target_compile_options(PolymorphNetwork PRIVATE /W4 /wd4250)
3031
endif()
3132
endif()
3233

docs/TCP.md

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,24 @@ As mentioned in the [README](/readme.md), the library has 2 major class that you
55

66
For readability’s sake, namespaces `polymorph::network::` and `polymorph::network::tcp::` will be omitted but keep in mind you need to mention them or use the following directive :
77
```c++
8-
using namespace polymorph::networ;
8+
using namespace polymorph::network;
99
using namespace polymorph::network::tcp;
1010
```
1111
1212
1313
## Server
1414
1515
### 1) Creating a server
16-
The `Server` have a constructor that takes a port and a `SessionStore` as parameters. You can create a new Session for the server sake or use one that is already used by **ONE UDP server**.
17-
```cpp
18-
SessionStore sessionStoreServer; // Session store of the server (store any client connection)
19-
// Then, you can create the server
20-
// Simply pass the session store, the mapping and the port you want the server to use
21-
Server server(4242, sessionStoreServer);
16+
The `Server` has a construction method create that takes a port as parameter. It retiurns a `std::unique_ptr<Server>` that you will have to store as long as you want the server to be running.
17+
```c++
18+
// Create a server on port 4242
19+
std::unique_ptr<Server> server = Server::create(4242);
2220
```
2321

2422
### 2) Register packet handlers
2523
You can now register callbacks to handle received packet. Here is an example of registering a callback for a packet with a payload of type `SampleDto` :
2624
```c++
27-
server.registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader &header, const APyaloadType &payload) {
25+
server->registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader &header, const APyaloadType &payload) {
2826
std::cout << "Server received \"" << payload.value << "\" from client with session id " << header.sId << std::endl;
2927
return true; // or false if you want to disconnect the client
3028
});
@@ -36,31 +34,32 @@ It is recommended to put a public static variable in all your DTOs to always hav
3634
### 3) Start the server
3735
Now you will have to start it in order to accept incoming connections. To do so, call the `Server::start()` method.
3836
```cpp
39-
server.start();
37+
server->start();
4038
```
4139

4240
### 4) Send packets
4341
You can now send packets to your clients. To do so, you will have to get the `SessionId` of the client you want to send a packet to. You can find it in received packet callbacks in the header.
4442
```cpp
45-
server.sendTo<SampleDto>(SampleDto::opId, payload, clientSessionId, [](const PacketHEader &header, const SampleDto &payload) {
43+
server->sendTo<SampleDto>(SampleDto::opId, payload, clientSessionId, [](const PacketHEader &header, const SampleDto &payload) {
4644
std::cout << "Server sent packet to client" << std::endl;
4745
});
4846
// or, to send to all clients
49-
server.send(SampleDto::opId, payload);
47+
server->send(SampleDto::opId, payload);
5048
```
5149
5250
## Client
5351
5452
### 1) Creating a client
55-
The `Client` have a constructor that takes a host string and a port as parameters . You have to pass the address and the port of a running (or soon) server.
53+
The `Client` has a construction method `create` that takes a host string and a port as parameters . You have to pass the address and the port of a running (or soon) server.
54+
It retiurns a `std::unique_ptr<Client>` that you will have to store as long as you want the client to be running.
5655
```cpp
57-
Client client("127.0.0.1", 4242);
56+
std::unique_ptr<Client> client = Client::create("127.0.0.1", 4242);
5857
```
5958

6059
### 2) Registering callbacks
6160
You can now register callbacks to handle received packet. Here is an example of registering a callback for a packet with a payload of type `SampleDto` :
6261
```c++
63-
client.registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader &header, const APyaloadType &payload) {
62+
client->registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader &header, const APyaloadType &payload) {
6463
std::cout << "Client received : " << payload.value << std::endl;
6564
return true; // or false if you want to disconnect the client
6665
});
@@ -69,7 +68,7 @@ client.registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader
6968
### 3) Connecting to the server
7069
You can now call the `Client::connect()` to initiate the connection with the server. You pass a callback which will be called when the server has accepted/refused the connection.
7170
```c++
72-
client.connect([](bool authorized, SessionId id) {
71+
client->connect([](bool authorized, SessionId id) {
7372
if (authorized) {
7473
std::cout << "Connected with session id " << id << std::endl;
7574
} else {
@@ -83,7 +82,7 @@ You can now send packets to the server. Here is an example of sending a packet w
8382
```c++
8483
SampleDto payload;
8584
payload.value = 42;
86-
client.send(SampleDto::opId, payload, [](const PacketHeader &header, const SampleDto &payload) {
85+
client->send(SampleDto::opId, payload, [](const PacketHeader &header, const SampleDto &payload) {
8786
std::cout << "Client sent packet to server";
8887
});
8988
```

docs/UDP.md

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Polymorph Network Library (UDP part)
22
> Here is the documentation for the UDP part. If you want to implement an TCP connection check [this](TCP.md) out.
33
4-
As mentioned in the [README](/readme.md), the library has 2 major class that you will have to instantiate. For UDP those class are `polymorph::network::udp::Server` and `polymorph::network::udp::Client`. There is also `polymorph::network::udp::Connector` which is really important as it handles send and receive operations
4+
As mentioned in the [README](/readme.md), the library has 2 major class that you will have to instantiate. For UDP those class are `polymorph::network::udp::Server` and `polymorph::network::udp::Client`.
55

66
For readability’s sake, namespaces `polymorph::network::` and `polymorph::network::udp::` will be omitted but keep in mind you need to mention them or use the following directive :
77
```c++
8-
using namespace polymorph::networ;
8+
using namespace polymorph::network;
99
using namespace polymorph::network::udp;
1010
```
1111
@@ -17,23 +17,16 @@ This is why you have to create a "safeties mapping", which is a map of `OpId` to
1717
## Server
1818
1919
### 1) Creating a server
20-
The `Server` have a constructor that takes a port and a `SessionStore` as parameters. You can create a new Session for the server sake or use one that is already used by **ONE UDP server**.
21-
You will also have to create a connector with a reference of the created server. Then, you will have to reference the connector in the server with the `Server::setConnector(std::shared_ptr<Connector>)` method.
20+
The `Server` has a construction method `create` that takes a port as parameter.
2221
```cpp
23-
SessionStore sessionStoreServer; // Session store of the server (store any client connection)
24-
// Then, you can create the server
25-
// Simply pass the session store, the mapping and the port you want the server to use
26-
22+
//create the safeties map
2723
std::map<OpId, bool> safetiesMapping = {
2824
{ SampleDto::opId, true }, // SampleDto is an important packet, it will be resent if we do not receive a confirmation of its reception. It will also send an ACK packet if the server receives a packet with this OpId
2925
{ AnotherDto::opId, false } // This packet is not important, it will be sent once
3026
};
3127
32-
Server server(4242, safetiesMapping, sessionStoreServer);
33-
// Then, you have to create a connector
34-
auto connector = std::make_shared<Connector>(server);
35-
// And finally, you have to reference the connector in the server
36-
server.setConnector(connector);
28+
// Then create the server that will listen on port 4242
29+
std::unique_ptr<Server> server = Server::create(4242, safetiesMapping);
3730
```
3831
It is recommended to put a public static variable in all your DTOs to always have their associated opId. This is why ```SampleDto::opId``` is used in the snippet.
3932

@@ -50,18 +43,15 @@ server->registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader
5043
🎉 Congratulations, you have created your server and registered your first callback !
5144

5245
### 3) Start the server
53-
Now you will have to start it in order to accept incoming connections. To do so, call the `Connector::start()` method.
54-
> __Warning__
55-
> Event if there is a `Server::start()` method, you have to call the `Connector::start()` method. This is because the server is not the one that will handle the incoming connections, it is the connector. The server will only handle the packets received by the connector.
56-
46+
Now you will have to start it in order to accept incoming connections.
5747
```c++
58-
connector->start();
48+
server->start();
5949
```
6050

6151
### 4) Send packets
6252
You can now send packets to your clients. To do so, you will have to get the `SessionId` of the client you want to send a packet to. You can find it in received packet callbacks in the header.
6353
```cpp
64-
server.sendTo<SampleDto>(SampleDto::opId, payload, clientSessionId, [](const PacketHEader &header, const SampleDto &payload) {
54+
server->sendTo<SampleDto>(SampleDto::opId, payload, clientSessionId, [](const PacketHEader &header, const SampleDto &payload) {
6555
std::cout << "Server sent packet to client" << std::endl;
6656
});
6757
// or, to send to all clients
@@ -71,21 +61,21 @@ server.send(SampleDto::opId, payload);
7161
## Client
7262

7363
### 1) Creating a client
74-
The `Client` have a constructor that takes a host string, a port and a `std::map<OpId, bool>` as parameters . You have to pass the address and the port of a running (or soon) server.
75-
The safety mapping should be the same as the one used by the server. You will also have to create a connector with a reference of the created client. Then, you will have to reference the connector in the client with the `Client::setConnector(std::shared_ptr<Connector>)` method.
64+
The `Client` has a construction method that takes a host string, a port and a `std::map<OpId, bool>` as parameters . You have to pass the address and the port of a running (or soon) server.
65+
The safety mapping should be the same as the one used by the server. You will also have to create a connector with a reference of the created client.
7666
```cpp
7767
std::map<OpId, bool> safetiesMapping = {
7868
{ SampleDto::opId, true }, // SampleDto is an important packet, it will be resent if we do not receive a confirmation of its reception. It will also send an ACK packet if the client receives a packet with this OpId
7969
{ AnotherDto::opId, false } // This packet is not important, it will be sent once
8070
};
8171

82-
Client client("127.0.0.1", 4242, safetiesMapping);
72+
std::unique_ptr<Client> client = Client::create("127.0.0.1", 4242, safetiesMapping);
8373
```
8474

8575
### 2) Registering callbacks
8676
You can now register callbacks to handle received packet. Here is an example of registering a callback for a packet with a payload of type `SampleDto` :
8777
```c++
88-
client.registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader &header, const APyaloadType &payload) {
78+
client->registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader &header, const APyaloadType &payload) {
8979
std::cout << "Client received : " << payload.value << std::endl;
9080
// Note that before calling the callback, the client will check if the packet is important or not. If it is, it will send an ACK packet
9181
});
@@ -94,7 +84,7 @@ client.registerReceiveHandler<SampleDto>(SampleDto::opId, [](const PacketHeader
9484
### 3) Connecting to the server
9585
You can now call the `Client::connect()` to initiate the connection with the server. You pass a callback which will be called when the server has accepted/refused the connection.
9686
```c++
97-
client.connect([](bool authorized, SessionId id) {
87+
client->connect([](bool authorized, SessionId id) {
9888
if (authorized) {
9989
std::cout << "Connected with session id " << id << std::endl;
10090
} else {
@@ -108,7 +98,7 @@ You can now send packets to the server. Here is an example of sending a packet w
10898
```c++
10999
SampleDto payload;
110100
payload.value = 42;
111-
client.send(SampleDto::opId, payload, [](const PacketHeader &header, const SampleDto &payload) {
101+
client->send(SampleDto::opId, payload, [](const PacketHeader &header, const SampleDto &payload) {
112102
std::cout << "Client sent packet to server";
113103
});
114104
```

examples/tcpEcho/echoClient.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#include <iostream>
2+
#include <atomic>
3+
#include <thread>
4+
#include <cassert>
25
#include "polymorph/network/tcp/Client.hpp"
36
#include "MessageDto.hpp"
47

@@ -14,22 +17,22 @@ int main(int ac, char **av)
1417
}
1518

1619
// we create a client and bind its connector
17-
Client client(av[1], std::stoi(av[2]));
20+
auto client = Client::create(av[1], std::stoi(av[2]));
1821

1922
// check variables for the example
2023
std::atomic<bool> received(false);
2124
std::atomic<bool> connected(false);
2225
MessageDto dto { .message = "Hello World!" };
2326

2427
// we register a callback that will handle the received MessageDto
25-
client.registerReceiveHandler<MessageDto>(MessageDto::opId, [&received](const PacketHeader &, const MessageDto &payload) {
28+
client->registerReceiveHandler<MessageDto>(MessageDto::opId, [&received](const PacketHeader &, const MessageDto &payload) {
2629
received = true;
2730
std::cout << "Received: " << payload.message << std::endl;
2831
return true; // The received data is correct, we do not want to disconnect the client
2932
});
3033

3134
// Then we connect to the server and pass a callback that will be called when the connection is established
32-
client.connect([&connected](bool authorized, SessionId) {
35+
client->connect([&connected](bool authorized, SessionId) {
3336
if (authorized) {
3437
std::cout << "Connected" << std::endl;
3538
connected = true;
@@ -46,7 +49,7 @@ int main(int ac, char **av)
4649
assert(connected); // abort if we couldn't connect
4750

4851
// we send the MessageDto to the server
49-
client.send<MessageDto>(MessageDto::opId, dto, [](const PacketHeader &header, const MessageDto &payload) {
52+
client->send<MessageDto>(MessageDto::opId, dto, [](const PacketHeader &header, const MessageDto &payload) {
5053
std::cout << "Message has been sent" << std::endl;
5154
});
5255

examples/tcpEcho/echoServer.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,21 @@ int main(int ac, char **av)
1414
return 1;
1515
}
1616

17-
// we create a SessionStore that will attribute the sessions
18-
SessionStore sessionStore;
1917
// we create a server and bind its connector
20-
Server server(std::stoi(av[1]), sessionStore);
18+
auto server = Server::create(std::stoi(av[1]));
2119

2220
// we register a callback that will handle the received MessageDto and send it back to the client
23-
server.registerReceiveHandler<MessageDto>(MessageDto::opId, [&server](const PacketHeader &header, const MessageDto &payload) {
21+
server->registerReceiveHandler<MessageDto>(MessageDto::opId, [&server](const PacketHeader &header, const MessageDto &payload) {
2422
std::cout << "Received: " << payload.message << std::endl;
2523
MessageDto toResend = payload;
26-
server.sendTo<MessageDto>(MessageDto::opId, toResend, header.sId, [](const PacketHeader &header, const MessageDto &payload) {
24+
server->sendTo<MessageDto>(MessageDto::opId, toResend, header.sId, [](const PacketHeader &header, const MessageDto &payload) {
2725
std::cout << "Message has been echoed" << std::endl;
2826
});
2927
return true; // The received data is correct, we do not want to disconnect the client
3028
});
3129

3230
// we start the server
33-
server.start();
31+
server->start();
3432

3533
// make the main thread sleep forever
3634
std::promise<void> p;

examples/udpEcho/echoClient.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
#include <iostream>
2+
#include <map>
3+
#include <memory>
4+
#include <atomic>
5+
#include <thread>
6+
#include <cassert>
27
#include "polymorph/network/udp/Client.hpp"
38
#include "MessageDto.hpp"
49

@@ -17,24 +22,21 @@ int main(int ac, char **av)
1722
{ MessageDto::opId, true } // we want the client to resend the message if it doesn't receive an ACK
1823
};
1924
// we create a client and bind its connector
20-
Client client(av[1], std::stoi(av[2]), safeties);
21-
auto connector = std::make_shared<Connector>(client);
22-
client.setConnector(connector);
23-
connector->start();
25+
auto client = Client::create(av[1], std::stoi(av[2]), safeties);
2426

2527
// check variables for the example
2628
std::atomic<bool> received(false);
2729
std::atomic<bool> connected(false);
2830
MessageDto dto { .message = "Hello World!" };
2931

3032
// we register a callback that will handle the received MessageDto
31-
client.registerReceiveHandler<MessageDto>(MessageDto::opId, [&received](const PacketHeader &, const MessageDto &payload) {
33+
client->registerReceiveHandler<MessageDto>(MessageDto::opId, [&received](const PacketHeader &, const MessageDto &payload) {
3234
received = true;
3335
std::cout << "Received: " << payload.message << std::endl;
3436
});
3537

3638
// Then we connect to the server and pass a callback that will be called when the connection is established
37-
client.connect([&connected](bool authorized, SessionId) {
39+
client->connect([&connected](bool authorized, SessionId) {
3840
if (authorized) {
3941
std::cout << "Connected" << std::endl;
4042
connected = true;
@@ -51,7 +53,7 @@ int main(int ac, char **av)
5153
assert(connected); // abort if we couldn't connect
5254

5355
// we send the MessageDto to the server
54-
client.send<MessageDto>(MessageDto::opId, dto, [](const PacketHeader &header, const MessageDto &payload) {
56+
client->send<MessageDto>(MessageDto::opId, dto, [](const PacketHeader &header, const MessageDto &payload) {
5557
std::cout << "Message has been sent" << std::endl;
5658
});
5759

examples/udpEcho/echoServer.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,19 @@ int main(int ac, char **av)
1717
std::map<OpId, bool> safeties = {
1818
{ MessageDto::opId, true } // we want the server to resend the message if it doesn't receive an ACK
1919
};
20-
// we create a SessionStore that will attribute the sessions
21-
SessionStore sessionStore;
22-
// we create a server and bind its connector
23-
Server server(std::stoi(av[1]), safeties, sessionStore);
24-
auto connector = std::make_shared<Connector>(server);
25-
server.setConnector(connector);
20+
auto server = Server::create(std::stoi(av[1]), safeties);
2621

2722
// we register a callback that will handle the received MessageDto and send it back to the client
28-
server.registerReceiveHandler<MessageDto>(MessageDto::opId, [&server](const PacketHeader &header, const MessageDto &payload) {
23+
server->registerReceiveHandler<MessageDto>(MessageDto::opId, [&server](const PacketHeader &header, const MessageDto &payload) {
2924
std::cout << "Received: " << payload.message << std::endl;
3025
MessageDto toResend = payload;
31-
server.sendTo<MessageDto>(MessageDto::opId, toResend, header.sId, [](const PacketHeader &header, const MessageDto &payload) {
26+
server->sendTo<MessageDto>(MessageDto::opId, toResend, header.sId, [](const PacketHeader &header, const MessageDto &payload) {
3227
std::cout << "Message has been echoed" << std::endl;
3328
});
3429
});
3530

3631
// we start the server
37-
connector->start();
32+
server->start();
3833

3934
// make the main thread sleep forever
4035
std::promise<void> p;

include/polymorph/network/SessionStore.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ namespace polymorph::network
8383

8484
/////////////////////////////// METHODS /////////////////////////////////
8585
public:
86+
SessionStore &operator=(const SessionStore &other);
87+
8688
void copyTcpSessionsFrom(SessionStore &other);
8789

8890
void copyUdpSessionsFrom(SessionStore &other);

0 commit comments

Comments
 (0)