Skip to content

Commit a672d97

Browse files
author
Alexandre jublot
committed
docs: added echo server and client examples
1 parent 412f19d commit a672d97

File tree

6 files changed

+308
-0
lines changed

6 files changed

+308
-0
lines changed

examples/tcpEcho/MessageDto.hpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
** EPITECH PROJECT, 2020
3+
** MessageDto.hpp
4+
** File description:
5+
** header for MessageDto.c
6+
*/
7+
8+
#pragma once
9+
10+
#include <string>
11+
#include "Polymorph/Network/SerializerTrait.hpp"
12+
13+
/**
14+
* @brief Message DTO that will be sent over the network
15+
*/
16+
#ifdef _WIN32
17+
#pragma pack(push, 1)
18+
#endif
19+
struct MessageDto
20+
{
21+
static constexpr polymorph::network::OpId opId = 3;
22+
std::string message;
23+
}
24+
#ifdef _WIN32
25+
;
26+
#pragma pack(pop)
27+
#else
28+
__attribute__((packed));
29+
#endif
30+
31+
/**
32+
* @brief SerializerTrait specialization for MessageDto because is it not a standard layout type
33+
*/
34+
namespace polymorph::network
35+
{
36+
template<>
37+
struct SerializerTrait<MessageDto>
38+
{
39+
static std::vector<std::byte> serialize(const MessageDto &data)
40+
{
41+
std::vector<std::byte> buffer(data.message.size());
42+
43+
std::memcpy(buffer.data(), data.message.data(), data.message.size());
44+
return buffer;
45+
}
46+
47+
static MessageDto deserialize(const std::vector<std::byte> &buffer)
48+
{
49+
MessageDto dto;
50+
51+
dto.message = std::string(reinterpret_cast<const char *>(buffer.data()), buffer.size());
52+
return dto;
53+
}
54+
};
55+
}
56+

examples/tcpEcho/echoClient.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include <iostream>
2+
#include "Polymorph/Network/tcp/Client.hpp"
3+
#include "MessageDto.hpp"
4+
5+
6+
int main(int ac, char **av)
7+
{
8+
using namespace polymorph::network;
9+
using namespace polymorph::network::tcp;
10+
11+
if (ac != 3) {
12+
std::cerr << "Usage: " << av[0] << " <host> <port>" << std::endl;
13+
return 1;
14+
}
15+
16+
// we create a client and bind its connector
17+
Client client(av[1], std::stoi(av[2]));
18+
19+
// check variables for the example
20+
std::atomic<bool> received(false);
21+
std::atomic<bool> connected(false);
22+
MessageDto dto { .message = "Hello World!" };
23+
24+
// we register a callback that will handle the received MessageDto
25+
client.registerReceiveHandler<MessageDto>(MessageDto::opId, [&received](const PacketHeader &, const MessageDto &payload) {
26+
received = true;
27+
std::cout << "Received: " << payload.message << std::endl;
28+
return true; // The received data is correct, we do not want to disconnect the client
29+
});
30+
31+
// 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) {
33+
if (authorized) {
34+
std::cout << "Connected" << std::endl;
35+
connected = true;
36+
} else {
37+
std::cout << "Connection failed" << std::endl;
38+
}
39+
});
40+
41+
// we wait for the connection to be established or the timeout to be reached (5 * 100ms)
42+
int connected_max_tries = 5;
43+
while (!connected && --connected_max_tries > 0) {
44+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
45+
}
46+
assert(connected); // abort if we couldn't connect
47+
48+
// we send the MessageDto to the server
49+
client.send<MessageDto>(MessageDto::opId, dto, [](const PacketHeader &header, const MessageDto &payload) {
50+
std::cout << "Message has been sent" << std::endl;
51+
});
52+
53+
// we wait the registered callback to be called
54+
while(!received)
55+
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // sleep until we received the echoed message
56+
57+
return 0;
58+
}

examples/tcpEcho/echoServer.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <iostream>
2+
#include <future>
3+
#include "Polymorph/Network/tcp/Server.hpp"
4+
#include "MessageDto.hpp"
5+
6+
7+
int main(int ac, char **av)
8+
{
9+
using namespace polymorph::network;
10+
using namespace polymorph::network::tcp;
11+
12+
if (ac != 2) {
13+
std::cerr << "Usage: " << av[0] << " <port>" << std::endl;
14+
return 1;
15+
}
16+
17+
// we create a SessionStore that will attribute the sessions
18+
SessionStore sessionStore;
19+
// we create a server and bind its connector
20+
Server server(std::stoi(av[1]), sessionStore);
21+
22+
// 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) {
24+
std::cout << "Received: " << payload.message << std::endl;
25+
MessageDto toResend = payload;
26+
server.sendTo<MessageDto>(MessageDto::opId, toResend, header.sId, [](const PacketHeader &header, const MessageDto &payload) {
27+
std::cout << "Message has been echoed" << std::endl;
28+
});
29+
return true; // The received data is correct, we do not want to disconnect the client
30+
});
31+
32+
// we start the server
33+
server.start();
34+
35+
// make the main thread sleep forever
36+
std::promise<void> p;
37+
p.get_future().wait();
38+
39+
return 0;
40+
}

examples/udpEcho/MessageDto.hpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
** EPITECH PROJECT, 2020
3+
** MessageDto.hpp
4+
** File description:
5+
** header for MessageDto.c
6+
*/
7+
8+
#pragma once
9+
10+
#include <string>
11+
#include "Polymorph/Network/SerializerTrait.hpp"
12+
13+
/**
14+
* @brief Message DTO that will be sent over the network
15+
*/
16+
struct MessageDto
17+
{
18+
static constexpr polymorph::network::OpId opId = 3;
19+
std::string message;
20+
};
21+
22+
/**
23+
* @brief SerializerTrait specialization for MessageDto because is it not a standard layout type
24+
*/
25+
namespace polymorph::network
26+
{
27+
template<>
28+
struct SerializerTrait<MessageDto>
29+
{
30+
static std::vector<std::byte> serialize(const MessageDto &data)
31+
{
32+
std::vector<std::byte> buffer(data.message.size());
33+
34+
std::memcpy(buffer.data(), data.message.data(), data.message.size());
35+
return buffer;
36+
}
37+
38+
static MessageDto deserialize(const std::vector<std::byte> &buffer)
39+
{
40+
MessageDto dto;
41+
42+
dto.message = std::string(reinterpret_cast<const char *>(buffer.data()), buffer.size());
43+
return dto;
44+
}
45+
};
46+
}
47+

examples/udpEcho/echoClient.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include <iostream>
2+
#include "Polymorph/Network/udp/Client.hpp"
3+
#include "MessageDto.hpp"
4+
5+
6+
int main(int ac, char **av)
7+
{
8+
using namespace polymorph::network;
9+
using namespace polymorph::network::udp;
10+
11+
if (ac != 3) {
12+
std::cerr << "Usage: " << av[0] << " <host> <port>" << std::endl;
13+
return 1;
14+
}
15+
16+
std::map<OpId, bool> safeties = {
17+
{ MessageDto::opId, true } // we want the client to resend the message if it doesn't receive an ACK
18+
};
19+
// 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();
24+
25+
// check variables for the example
26+
std::atomic<bool> received(false);
27+
std::atomic<bool> connected(false);
28+
MessageDto dto { .message = "Hello World!" };
29+
30+
// we register a callback that will handle the received MessageDto
31+
client.registerReceiveHandler<MessageDto>(MessageDto::opId, [&received](const PacketHeader &, const MessageDto &payload) {
32+
received = true;
33+
std::cout << "Received: " << payload.message << std::endl;
34+
});
35+
36+
// 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) {
38+
if (authorized) {
39+
std::cout << "Connected" << std::endl;
40+
connected = true;
41+
} else {
42+
std::cout << "Connection failed" << std::endl;
43+
}
44+
});
45+
46+
// we wait for the connection to be established or the timeout to be reached (5 * 100ms)
47+
int connected_max_tries = 5;
48+
while (!connected && --connected_max_tries > 0) {
49+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
50+
}
51+
assert(connected); // abort if we couldn't connect
52+
53+
// we send the MessageDto to the server
54+
client.send<MessageDto>(MessageDto::opId, dto, [](const PacketHeader &header, const MessageDto &payload) {
55+
std::cout << "Message has been sent" << std::endl;
56+
});
57+
58+
// we wait the registered callback to be called
59+
while(!received)
60+
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // sleep until we received the echoed message
61+
62+
return 0;
63+
}

examples/udpEcho/echoServer.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include <iostream>
2+
#include <future>
3+
#include "Polymorph/Network/udp/Server.hpp"
4+
#include "MessageDto.hpp"
5+
6+
7+
int main(int ac, char **av)
8+
{
9+
using namespace polymorph::network;
10+
using namespace polymorph::network::udp;
11+
12+
if (ac != 2) {
13+
std::cerr << "Usage: " << av[0] << " <port>" << std::endl;
14+
return 1;
15+
}
16+
17+
std::map<OpId, bool> safeties = {
18+
{ MessageDto::opId, true } // we want the server to resend the message if it doesn't receive an ACK
19+
};
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);
26+
27+
// 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) {
29+
std::cout << "Received: " << payload.message << std::endl;
30+
MessageDto toResend = payload;
31+
server.sendTo<MessageDto>(MessageDto::opId, toResend, header.sId, [](const PacketHeader &header, const MessageDto &payload) {
32+
std::cout << "Message has been echoed" << std::endl;
33+
});
34+
});
35+
36+
// we start the server
37+
connector->start();
38+
39+
// make the main thread sleep forever
40+
std::promise<void> p;
41+
p.get_future().wait();
42+
43+
return 0;
44+
}

0 commit comments

Comments
 (0)