diff --git a/CMakeLists.txt b/CMakeLists.txt
index 64c1b6d3bae478cc8548b2b3a5ea16e60a5a67c1..0939b6924dd9015980dfae3688073a0214f87578 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,7 @@ option(BUILD_DEPENDENCIES "Build dependencies" ON)
 option(DNC_SYSTEMD_UNIT_FILE_LOCATION "Where to install systemd unit file")
 option(DNC_SYSTEMD "Enable dnc systemd integration" ON)
 option(CODE_COVERAGE "Enable coverage reporting" OFF)
+option(BUILD_EXAMPLE "Build example" ON)
 
 # Check if testing is enabled
 if(BUILD_TESTING)
@@ -426,4 +427,17 @@ if (BUILD_TESTING AND NOT MSVC)
     #target_link_libraries(tests_stringutils PRIVATE dhtnet fmt::fmt PkgConfig::Cppunit)
     #add_test(NAME tests_stringutils COMMAND tests_stringutils)
 
+endif()
+if (BUILD_EXAMPLES AND NOT MSVC)
+    add_executable(server
+    example/server.cpp)
+    target_link_libraries(server PRIVATE dhtnet)
+    target_include_directories(server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/example)
+    install(TARGETS server RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+    add_executable(client
+    example/client.cpp)
+    target_link_libraries(client PRIVATE dhtnet)
+    target_include_directories(client PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/example)
+    install(TARGETS client RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
\ No newline at end of file
diff --git a/README.md b/README.md
index ab329ddbbad41ac525644432ffd4d382633dba0d..475dde2518d853737e724bb8d0f045a58bbdf8b1 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # DHTNet - Lightweight Peer-to-Peer Communication Library
 
-![DHTNet Logo](your-logo.png)
+![DHTNet Logo]()
 
 DHTNet is a C++17 library designed to serve as a network overlay that provides an IP network abstraction. Its main objective is to establish secure peer-to-peer connections using public-key authentication.
 
@@ -31,58 +31,9 @@ Get started with DHTNet by building and installing the library:
 - [Build and Install Instructions](BUILD.md)
 
 ## Usage Example
-
-```cpp
-#include "connectionmanager.h"
-#include <opendht/log.h>
-#include <opendht/utils.h>
-#include <opendht/thread_pool.h>
-#include <fmt/core.h>
-
-int main() {
-    // Create identities for CA (Certificate Authority), client, and server
-    auto ca = dht::crypto::generateIdentity("ca");
-    auto id_client = dht::crypto::generateIdentity("client", ca);
-    auto id_server = dht::crypto::generateIdentity("server", ca);
-
-    // Create client and server ConnectionManager instances
-    auto client = std::make_shared<ConnectionManager>(id_client);
-    auto server = std::make_shared<ConnectionManager>(id_server);
-
-    // Launch dht nodes
-    client->onDhtConnected(id_client.first->getPublicKey());
-    server->onDhtConnected(id_server.first->getPublicKey());
-
-    // Connect the client to the server's device via a channel named "channelName"
-    client->connectDevice(id_server.second->getId(), "channelName", [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
-                                                const dht::InfoHash&) {
-        if (socket) {
-            // Send a message (example: "Hello") to the server
-            std::error_code ec;
-            std::string data = "hello";
-            socket->write(data.data(), data.size(), ec);
-        }
-    });
-
-    // Define a callback function for when the server's connection is ready
-    server->onConnectionReady([&](const DeviceId& device, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
-        if (socket) {
-            // Server: Connection succeeded
-            fmt::print("Server: Connection succeeded\n");
-
-            // Set a callback for receiving messages
-            socket->setOnRecv([&](const uint8_t* data, size_t size) {
-               fmt::print("Message received: {}\n", std::string_view(data, data + size)); // Print received message
-            });
-        } else {
-            // Server: Connection failed
-            fmt::print("Server: Connection failed\n");
-        }
-    });
-
-    return 0;
-}
-```
+In the example repository, there is a client-server application where the client connects to the server and sends a "hello" message.
+You can build the example using the project's [Build and Install Instructions](BUILD.md) with `-BUILS_EXAMPLE=ON`.
+![Demo](example/client-server_dhtnet.png)
 
 ## Dependencies
 
diff --git a/example/client-server_dhtnet.png b/example/client-server_dhtnet.png
new file mode 100644
index 0000000000000000000000000000000000000000..de6ea40a3210752455551800e986217ab5496ac5
Binary files /dev/null and b/example/client-server_dhtnet.png differ
diff --git a/example/client.cpp b/example/client.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..39073b65ed09012ad9e9cde226495ba4035ffb99
--- /dev/null
+++ b/example/client.cpp
@@ -0,0 +1,74 @@
+#include "certstore.h"
+#include "connectionmanager.h"
+#include "fileutils.h"
+
+#include <opendht/crypto.h>
+
+#include <string>
+#include <vector>
+
+namespace dhtnet {
+void
+client(dht::crypto::Identity id_client, dht::InfoHash id_server)
+{
+    fmt::print("Start client\n");
+    fmt::print("Client identity: {}\n", id_client.second->getId());
+
+    // Create client ConnectionManager instance
+    auto client = std::make_shared<ConnectionManager>(id_client);
+
+    // Launch dht node
+    client->onDhtConnected(id_client.first->getPublicKey());
+
+    // Connect the client to the server's device via a channel named "channelName"
+    client->connectDevice(id_server,
+                          "channelName",
+                          [&](std::shared_ptr<ChannelSocket> socket, const dht::InfoHash&) {
+                              fmt::print("Client: Sending request\n");
+                              if (socket) {
+                                  // Send a message (example: "Hello") to the server
+                                  std::error_code ec;
+                                  std::string msg = "hello";
+                                  fmt::print("Client: Sending message: {}\n", msg);
+                                  std::vector<unsigned char> data(msg.begin(), msg.end());
+
+                                  socket->write(data.data(), data.size(), ec);
+                                  // For continuous data transmission, refer to the readFromPipe
+                                  // function in tools/common.cpp
+                                  if (ec) {
+                                      fmt::print("Client: Error writing to socket: {}\n",
+                                                 ec.message());
+                                  } else {
+                                      fmt::print("Client: Message sent\n");
+                                  }
+                              } else {
+                                  fmt::print("Client: Connection failed\n");
+                                  return;
+                              }
+                          });
+
+    // keep the client running
+    while (true) {
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+    }
+}
+} // namespace dhtnet
+
+int
+main(int argc, char** argv)
+{
+    // Set the log level to 0 to avoids pj logs
+    pj_log_set_level(0);
+
+    // This is the root certificate that will be used to sign other certificates
+    auto ca = dht::crypto::generateIdentity("ca_client");
+
+    auto id_client = dht::crypto::generateIdentity("client", ca);
+
+    auto id_server = dht::InfoHash(argv[1]);
+
+    dhtnet::client(id_client, id_server);
+
+
+    return 0;
+}
\ No newline at end of file
diff --git a/example/server.cpp b/example/server.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0ace5fe7878688d327acf493dc95793c66779a6c
--- /dev/null
+++ b/example/server.cpp
@@ -0,0 +1,85 @@
+
+#include "connectionmanager.h"
+#include "fileutils.h"
+
+#include <opendht/log.h>
+#include <opendht/crypto.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+#include <string_view>
+namespace dhtnet {
+void
+server(dht::crypto::Identity id_server)
+{
+    fmt::print("Server identity: {}\n", id_server.second->getId());
+    // Create an instance of ConnectionManager for the server
+    auto server = std::make_shared<ConnectionManager>(id_server);
+
+    fmt::print("Start server\n");
+    // Start the DHT node for the server
+    server->onDhtConnected(id_server.first->getPublicKey());
+
+    // Handle ICE connection requests from devices
+    // This callback is triggered when a device requests an ICE connection.
+    // The callback should decide whether to accept or decline the request.
+    server->onICERequest([id_server](const DeviceId& device) {
+        // Optional: Add logic to validate the device's certificate
+        // Example: Check if the device's certificate is signed by a trusted authority
+        // In this example, all devices are allowed to connect
+        fmt::print("Server: ICE request received from {}\n", device.toString());
+        return true;
+    });
+
+    // Handle requests for establishing a communication channel
+    // The callback checks if the channel should be opened based on the name or device's certificate.
+    server->onChannelRequest(
+        [&](const std::shared_ptr<dht::crypto::Certificate>& cert, const std::string& name) {
+            // Optional: Add logic to validate the channel name or certificate
+            // Example: Allow the connection if the channel name is "channelName"
+            fmt::print("Server: Channel request received from {}\n", cert->getLongId());
+            return name == "channelName";
+        });
+
+    // Define a callback when the connection is established
+    server->onConnectionReady([&](const DeviceId& device,
+                                  const std::string& name,
+                                  std::shared_ptr<ChannelSocket> socket) {
+        if (socket) {
+            fmt::print("Server: Connection succeeded\n");
+            // Set up a callback to handle incoming messages on this connection
+            socket->setOnRecv([socket](const uint8_t* data, size_t size) {
+                fmt::print("Server: Received message: {}\n", std::string((const char*) data, size));
+                return size;
+            });
+        } else {
+            // The connection failed
+            fmt::print("Server: Connection failed\n");
+        }
+    });
+
+    // Keep the server running indefinitely
+    while (true) {
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+    }
+}
+
+} // namespace dhtnet
+
+int
+main()
+{
+    // Set the log level to 0 to avoids pj logs
+    pj_log_set_level(0);
+
+    // This is the root certificate that will be used to sign other certificates
+    auto ca = dht::crypto::generateIdentity("ca");
+
+    auto id_server = dht::crypto::generateIdentity("server", ca);
+
+    dhtnet::server(id_server);
+
+    return 0;
+}
\ No newline at end of file