### C++ libnio Server Example Source: https://github.com/acl-dev/libnio/blob/main/README.md This C++ example demonstrates how to set up a non-blocking server using libnio. It handles client connections asynchronously, managing read, write, error, and close events. It requires the libnio library and standard C++ headers. The server listens on a specified IP and port, processing client I/O in a loop. ```C++ #include #include #include #include #include #include "nio/nio_event.hpp" #include "nio/client_socket.hpp" #include "nio/server_socket.hpp" using namespace nio; // Handle client IO process in async mode. static void handle_client(client_socket *cli, int timeout) { (*cli).on_read([cli, timeout](socket_t fd, bool expired) { if (expired) { printf("Read timeout for fd %d\r\n", fd); cli->close_await(); return; } char buf[1204]; ssize_t ret = cli->read(fd, buf, sizeof(buf)); if (ret <= 0 || cli->write(buf, ret, timeout) == -1) { cli->close_await(); } }).on_write([cli](socket_t fd, bool expired) { if (expired) { printf("Write expired for fd %d\r\n", fd); cli->close_await(); } }).on_error([cli](socket_t fd) { cli->close_await(); }).on_close([cli](socket_t fd) { printf("Closing client fd %d\r\n", fd); delete cli; return true; // Return true to show that the client can be closed. }); // Add async read event. cli->read_await(timeout); } int main() { std::string ip("127.0.0.1"); int port = 8288, timeout = 5000; nio_event_t etype = NIO_EVENT_T_KERNEL; // Ignore SIGPIPE to avoid process exit. signal(SIGPIPE, SIG_IGN); nio_event::debug(true); nio_event ev(102400, etype); server_socket server; // Bind and listen the specified address. if (!server.open(ip.c_str(), port)) { printf("Listen on %s:%d error\r\n", ip.c_str(), port); return 1; } printf("Listen on %s:%d ok\r\n", ip.c_str(), port); // Register callback handlers in server. server.set_on_accept([&ev, timeout](socket_t fd, const std::string &addr) { printf("Accept on client from %s, fd: %d\r\n", addr.c_str(), fd); auto *cli = new client_socket(ev, fd); handle_client(cli, timeout); }).set_on_error([]() { printf("Error on server socket\r\n"); }).set_on_close([]() { printf("Server socket closed\r\n"); }); // The server socket will accecpt client connections in async mode. server.accept_await(ev); // IO event loop process. while (true) { ev.wait(1000); } return 0; } ``` -------------------------------- ### CMake: Source Directory and Include Path Setup Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/timer/CMakeLists.txt Defines the base path for source files and sets up include directories. It uses a loop to find all source files within the specified directories and includes both project-specific and external include paths. ```cmake set(home_path ${CMAKE_CURRENT_SOURCE_DIR}/../..) set(cpp_inc ${home_path}/cpp/include) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${cpp_inc} ) set(base_path ${CMAKE_CURRENT_SOURCE_DIR}) set(src_paths ${base_path}) foreach(iter ${src_paths}) aux_source_directory(${iter} src_files) endforeach() ``` -------------------------------- ### CMake: Basic Project Setup and Build Type Check Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/server2/CMakeLists.txt Initializes the CMake project, checks for in-source builds, and provides status messages based on the CMAKE_BUILD_TYPE (RELEASE, DEBUG, or default). ```cmake cmake_minimum_required(VERSION 3.2.0) project(server2) if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") message(STATUS "build server2 for release version") elseif (CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(STATUS "build server2 for debug version") else() message(STATUS "build server2 for default version") endif() ``` -------------------------------- ### C++ Asynchronous Client Socket Example using libnio Source: https://github.com/acl-dev/libnio/blob/main/README.md This C++ code demonstrates a client socket implementation using the libnio library. It showcases asynchronous connection, read, write, error, and close event handlers. The client connects to a specified IP and port, sends a 'hello world!' message, and echoes back any received data. It manages multiple concurrent connections and relies on libnio for event-driven I/O. ```C++ #include #include #include #include #include #include #include "nio/nio_event.hpp" #include "nio/client_socket.hpp" using namespace nio; static long long total_count = 10000; static long long count = 0; static int nconns = 0; static bool connect_server(nio_event &ev, const char *ip, int port, int timeout) { auto *cli = new client_socket(ev); (*cli).on_connect([cli, timeout](socket_t fd, bool expired) { if (fd == -1 || expired) { printf("Connect failed, fd=%d, %s\r\n", fd, expired ? "expired" : "error"); cli->close_await(); nconns--; return; } printf("Connect ok, fd %d\r\n", fd); const char *s = "hello world!\r\n"; if (cli->write( s, strlen(s), timeout) == -1) { cli->close_await(); } else { cli->read_await(timeout); } }).on_read([cli, timeout](socket_t fd, bool expired) { char buf[1024]; ssize_t ret = cli->read(fd, buf, sizeof(buf)); if (ret <= 0 || ++count >= total_count || cli->write(buf, ret, timeout) == -1) { cli->close_await(); } }).on_write([cli](socket_t fd, bool expired) { printf("Write wait %s for fd %d\r\n", expired ? "expired" : "error", fd); if (expired) { cli->close_await(); } }).on_error([cli](socket_t fd) { cli->close_await(); }).on_close([cli](socket_t fd) { delete cli; nconns--; return true; }); if (!cli->connect_await(ip, port, 5000)) { delete cli; return false; } return true; } int main() { int cocurrent = 100; std::string ip("127.0.0.1"); int port = 8288, timeout = 5000; nio_event_t etype = NIO_EVENT_T_KERNEL; signal(SIGPIPE, SIG_IGN); nio_event::debug(true); nio_event ev(102400, etype); for (int i = 0; i < cocurrent; i++) { if (!connect_server(ev, ip.c_str(), port, timeout)) { printf("Connect server error %s\r\n", strerror(errno)); break; } ++nconns; } struct timeval begin{0, 0}; gettimeofday(&begin, nullptr); while (nconns > 0) { ev.wait(1000); } return 0; } ``` -------------------------------- ### CMake: Basic Project Setup and Compiler Flags Source: https://github.com/acl-dev/libnio/blob/main/cpp/CMakeLists.txt Initializes the CMake project, sets the minimum required version, and defines essential compiler flags for optimization, position-independent code, warnings, and C++11 standard. It also includes platform-specific definitions for libraries like MySQL, SQLite, and Zlib. ```cmake cmake_minimum_required(VERSION 3.2.0) if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() add_definitions( "-W" "-O3" "-fPIC" "-Wall" "-Werror" "-Wshadow" "-Wformat" "-Wpointer-arith" "-D_REENTRANT" "-D_USE_FAST_MACRO" "-Wno-long-long" "-D_POSIX_PTHREAD_SEMANTICS" "-DHAS_MYSQL_DLL" "-DHAS_SQLITE_DLL" "-DHAS_ZLIB_DLL" "-Wno-unused-parameter" "-std=c++11" ) ``` -------------------------------- ### Basic CMake Project Setup and Build Type Configuration Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/client/CMakeLists.txt Initializes the CMake project and defines build behavior based on the CMAKE_BUILD_TYPE. It includes a check to prevent building in the source directory and provides status messages for release, debug, or default build types. ```cmake cmake_minimum_required(VERSION 3.2.0) project(client) if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") message(STATUS "build clientf release version") elseif (CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(STATUS "build client for debug version") else() message(STATUS "build client for default version") endif() ``` -------------------------------- ### CMake: Static Library Compilation and Installation Source: https://github.com/acl-dev/libnio/blob/main/cpp/CMakeLists.txt Compiles source files into a static library named 'nio_cpp_static' (output name 'nio_cpp'). It defines the library output path and installation rules for the static library archive and header files, excluding non-hpp files. ```cmake foreach(iter ${src}) aux_source_directory(${iter} lib_src) endforeach() if(NOT CMAKE_SYSTEM_NAME MATCHES "Android") set(lib_output_path ${CMAKE_CURRENT_SOURCE_DIR}/lib) set(LIBRARY_OUTPUT_PATH ${lib_output_path}) add_library(nio_cpp_static STATIC ${lib_src}) SET_TARGET_PROPERTIES(nio_cpp_static PROPERTIES OUTPUT_NAME "nio_cpp") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${lib_output_path}) link_directories(${lib_output_path}) install(TARGETS nio_cpp_static ARCHIVE DESTINATION /usr/local/lib) install(DIRECTORY include/nio DESTINATION /usr/local/include FILES_MATCHING PATTERN "*.hpp") endif() ``` -------------------------------- ### CMake: Add Subdirectories for Build Targets Source: https://github.com/acl-dev/libnio/blob/main/CMakeLists.txt Includes build configurations from various subdirectories for C, C++, and example applications. Each subdirectory likely contains its own CMakeLists.txt to define specific targets and dependencies. ```cmake add_subdirectory(c) add_subdirectory(cpp) add_subdirectory(samples-c++/timer) add_subdirectory(samples-c++/server) add_subdirectory(samples-c++/client) add_subdirectory(samples-c++/server2) add_subdirectory(samples-c++/client2) add_subdirectory(samples-c++/mqtt/mqtt_server) add_subdirectory(samples-c++/mqtt/mqtt_client) ``` -------------------------------- ### Event Timers: Periodic Tasks in C++ Source: https://context7.com/acl-dev/libnio/llms.txt This C++ code snippet demonstrates how to create custom timers that execute callbacks at specified intervals using the nio library. The example defines a `my_timer` class that inherits from `nio::event_timer` and is scheduled to trigger periodically. Each timer fires a set number of times before being deleted. ```cpp #include #include #include "nio/nio_event.hpp" #include "nio/event_timer.hpp" class my_timer : public nio::event_timer { public: my_timer(nio::nio_event& ev, int id, int max_count) : ev_(ev), id_(id), max_count_(max_count) { start_time_ = time(nullptr); } protected: void on_timer() override { count_++; printf("Timer %d triggered: count=%d, elapsed=%ld seconds\n", id_, count_, time(nullptr) - start_time_); if (count_ >= max_count_) { printf("Timer %d completed, deleting\n", id_); delete this; } else { // Re-schedule timer for 1000ms later ev_.add_timer(this, 1000); } } private: ~my_timer() override = default; nio::nio_event& ev_; int id_; int max_count_; int count_ = 0; time_t start_time_; }; int main() { nio::nio_event ev(10240); // Create 10 timers, each fires 5 times for (int i = 1; i <= 10; i++) { auto* timer = new my_timer(ev, i, 5); ev.add_timer(timer, 1000); // Schedule for 1000ms } while (true) { ev.wait(1000); } return 0; } ``` -------------------------------- ### CMake Source and Library Configuration for libnio Source: https://github.com/acl-dev/libnio/blob/main/c/CMakeLists.txt This snippet configures the source directories, include paths, and compiles the source files into a static library named 'nio'. It also sets up the output path for the library and specifies installation rules for the library archive and header files. ```cmake set(src ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/common ${CMAKE_CURRENT_SOURCE_DIR}/src/events ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/include ) foreach(iter ${src}) aux_source_directory(${iter} lib_src) endforeach() if(NOT CMAKE_SYSTEM_NAME MATCHES "Android") set(lib_output_path ${CMAKE_CURRENT_SOURCE_DIR}/lib) set(LIBRARY_OUTPUT_PATH ${lib_output_path}) add_library(nio_static STATIC ${lib_src}) SET_TARGET_PROPERTIES(nio_static PROPERTIES OUTPUT_NAME "nio") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${lib_output_path}) link_directories(${lib_output_path}) install(TARGETS nio_static ARCHIVE DESTINATION /usr/local/lib) install(DIRECTORY include/nio DESTINATION /usr/local/include FILES_MATCHING PATTERN "*.h") endif() ``` -------------------------------- ### MQTT Client Pub/Sub Messaging with C++ libnio Source: https://context7.com/acl-dev/libnio/llms.txt This C++ code snippet demonstrates the implementation of an MQTT client using the libnio library. It showcases how to establish a connection, subscribe to topics, publish messages, and handle incoming messages, including PINGREQ requests for maintaining the connection. The code also includes error handling and graceful connection closure. ```cpp #include #include #include "nio/nio_event.hpp" #include "nio/client_socket.hpp" #include "nio/mqtt/mqtt_client.hpp" #include "nio/mqtt/mqtt_message.hpp" #include "nio/mqtt/mqtt_pingreq.hpp" using namespace nio; static long long message_count = 0; static void handle_mqtt_client(client_socket *cli, int timeout) { auto *mqtt = new mqtt_client(*cli); // Handle incoming MQTT messages mqtt->on_message([mqtt](const mqtt_message &msg) { message_count++; if (message_count < 10) { printf("Received MQTT message #%lld\n", message_count); } if (message_count >= 10000) { printf("Reached message limit\n"); return false; // Stop processing } // Send PINGREQ message mqtt_pingreq ping; if (!mqtt->send_await(ping)) { printf("Failed to send PINGREQ\n"); return false; } return true; // Continue processing }).on_timeout([](mqtt_client &client) { printf("MQTT timeout on fd %d\n", client.get_conn().sock_handle()); return false; }); // Update close handler to clean up mqtt object (*cli).on_close([cli, mqtt](socket_t fd) { printf("Closing MQTT client fd %d\n", fd); delete mqtt; delete cli; return true; }); // Send initial message mqtt_pingreq initial_ping; if (!mqtt->send_await(initial_ping)) { printf("Failed to send initial PINGREQ\n"); cli->close_await(); return; } if (!mqtt->read_await(timeout)) { printf("Failed to start MQTT read\n"); cli->close_await(); return; } printf("MQTT client initialized, fd %d\n", cli->sock_handle()); } int main() { signal(SIGPIPE, SIG_IGN); nio_event::debug(true); nio_event ev(102400, NIO_EVENT_T_KERNEL); auto *cli = new client_socket(ev); (*cli).on_connect([cli](socket_t fd, bool expired) { if (fd == -1 || expired) { printf("MQTT connect failed\n"); cli->close_await(); return; } printf("MQTT connected, fd %d\n", fd); handle_mqtt_client(cli, 5000); }).on_error([cli](socket_t fd) { cli->close_await(); }).on_close([cli](socket_t fd) { printf("MQTT connection closed\n"); delete cli; return true; }); if (!cli->connect_await("127.0.0.1", 8288, 5000)) { printf("Failed to initiate MQTT connection\n"); delete cli; return 1; } while (true) { ev.wait(1000); } return 0; } ``` -------------------------------- ### TCP Server - Accept Connections Source: https://context7.com/acl-dev/libnio/llms.txt Sets up a TCP server that listens on a specified address and port. It handles incoming client connections asynchronously, registering callbacks for read, error, and close events. Client sockets are managed with timeouts for read operations. ```cpp #include #include #include "nio/nio_event.hpp" #include "nio/server_socket.hpp" #include "nio/client_socket.hpp" using namespace nio; static void handle_client(client_socket *cli, int timeout) { // Register read event handler (*cli).on_read([cli, timeout](socket_t fd, bool expired) { if (expired) { printf("Read timeout for fd %d\n", fd); cli->close_await(); return; } char buf[4096]; ssize_t ret = cli->read(buf, sizeof(buf)); if (ret <= 0 || cli->write(buf, ret, timeout) == -1) { cli->close_await(); } }).on_error([cli](socket_t fd) { printf("Error on fd %d\n", fd); cli->close_await(); }).on_close([cli](socket_t fd) { printf("Closing client fd %d\n", fd); delete cli; return true; }); // Start async read with 5 second timeout cli->read_await(timeout); } int main() { signal(SIGPIPE, SIG_IGN); nio_event ev(102400, NIO_EVENT_T_KERNEL); server_socket server; if (!server.open("127.0.0.1", 8288)) { printf("Failed to listen on 127.0.0.1:8288\n"); return 1; } printf("Server listening on 127.0.0.1:8288\n"); server.set_on_accept([&ev](socket_t fd, const std::string &addr) { printf("Accepted client from %s, fd: %d\n", addr.c_str(), fd); auto *cli = new client_socket(ev, fd); handle_client(cli, 5000); }).set_on_error([]() { printf("Server socket error\n"); }); server.accept_await(ev); while (true) { ev.wait(1000); } return 0; } ``` -------------------------------- ### CMake: Include Directories and Source File Collection Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/mqtt/mqtt_server/CMakeLists.txt This snippet sets up the project's include paths, including the current directory and a 'cpp/include' directory relative to the project root. It then collects all source files from the specified source directory into the 'src_files' variable. ```cmake set(home_path ${CMAKE_CURRENT_SOURCE_DIR}/../../..) set(cpp_inc ${home_path}/cpp/include) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${cpp_inc} ) set(base_path ${CMAKE_CURRENT_SOURCE_DIR}) set(src_paths ${base_path}) foreach(iter ${src_paths}) aux_source_directory(${iter} src_files) endforeach() ``` -------------------------------- ### CMake: Project and Build Type Configuration Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/mqtt/mqtt_server/CMakeLists.txt This snippet initializes the CMake project, sets the project name, and configures build behavior based on the CMAKE_BUILD_TYPE. It ensures the build directory is separate from the source directory and provides status messages for release, debug, or default builds. ```cmake cmake_minimum_required(VERSION 3.2.0) project(mqtt_server) if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") message(STATUS "build mqtt_server for release version") elseif (CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(STATUS "build mqtt_server for debug version") else() message(STATUS "build mqtt_server for default version") endif() ``` -------------------------------- ### Create and Run Event Loop Source: https://context7.com/acl-dev/libnio/llms.txt Initializes the libnio event system and enters a loop to process I/O events. It supports a maximum number of file descriptors and automatically selects the appropriate kernel event notification mechanism. Debug output can be enabled. ```cpp #include "nio/nio_event.hpp" using namespace nio; int main() { // Create event loop with max 10240 file descriptors // NIO_EVENT_T_KERNEL uses epoll/kqueue/iocp automatically nio_event ev(10240, NIO_EVENT_T_KERNEL); // Enable debug output nio_event::debug(true); // Main event loop - waits up to 1000ms for events while (true) { ev.wait(1000); } return 0; } ``` -------------------------------- ### CMake: Linking Libraries for Executable Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/mqtt/mqtt_server/CMakeLists.txt This snippet configures the libraries to be linked based on the operating system. It then sets the runtime output directory and links the collected source files to create the 'mqtt_server' executable, linking the necessary libraries including pthreads and dl. ```cmake if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) endif() set(output_path ${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${output_path}) link_directories(${output_path}) add_executable(mqtt_server ${src_files}) target_link_libraries(mqtt_server ${lib_all}) ``` -------------------------------- ### C API: Low-Level Event Operations for TCP Server Source: https://context7.com/acl-dev/libnio/llms.txt This C code snippet demonstrates setting up a basic TCP echo server using libnio's low-level C API. It includes event registration for listening and read events, handling client connections, reading data, and echoing it back. Dependencies include standard C libraries and libnio headers. It binds to 127.0.0.1:8288 and enters an event loop. ```c #include #include #include #include #include #include #include #include "nio/nio_event.h" #include "nio/nio_iostuff.h" static void read_callback(NIO_EVENT *ev, NIO_FILE *fe) { char buf[4096]; int ret = read(fe->fd, buf, sizeof(buf)); if (ret <= 0) { nio_event_del_readwrite(ev, fe); close(fe->fd); nio_file_free(fe); printf("Client disconnected\n"); } else { // Echo back to client if (write(fe->fd, buf, ret) <= 0) { nio_event_del_readwrite(ev, fe); close(fe->fd); nio_file_free(fe); } } } static void listen_callback(NIO_EVENT *ev, NIO_FILE *fe) { struct sockaddr_in sa; socklen_t len = sizeof(sa); socket_t cfd = accept(fe->fd, (struct sockaddr*)&sa, &len); if (cfd == -1) { printf("Accept error\n"); return; } printf("Accepted client, fd %d\n", cfd); nio_non_blocking(cfd, 1); nio_tcp_nodelay(cfd, 1); NIO_FILE *client_fe = nio_file_alloc(cfd); if (!nio_event_add_read(ev, client_fe, read_callback)) { printf("Failed to add read event for fd %d\n", cfd); close(cfd); nio_file_free(client_fe); } } int main() { signal(SIGPIPE, SIG_IGN); // Create socket manually socket_t lfd = socket(PF_INET, SOCK_STREAM, 0); int on = 1; setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = PF_INET; sa.sin_port = htons(8288); sa.sin_addr.s_addr = inet_addr("127.0.0.1"); if (bind(lfd, (struct sockaddr*)&sa, sizeof(sa)) < 0) { printf("Bind failed\n"); return 1; } if (listen(lfd, 128) < 0) { printf("Listen failed\n"); return 1; } printf("C API server listening on 127.0.0.1:8288\n"); // Create event loop - NIO_EVENT_TYPE_KERNEL uses epoll/kqueue NIO_EVENT *ev = nio_event_create(102400, NIO_EVENT_TYPE_KERNEL, 0); nio_event_debug(1); // Allocate file descriptor wrapper NIO_FILE *fe = nio_file_alloc(lfd); // Register listen socket for read events if (!nio_event_add_read(ev, fe, listen_callback)) { printf("Failed to add listen event\n"); return 1; } // Main event loop while (1) { nio_event_wait(ev, 1000); } nio_event_free(ev); return 0; } ``` -------------------------------- ### TCP Client: Connect and Send Data Async in C++ Source: https://context7.com/acl-dev/libnio/llms.txt This C++ code snippet demonstrates how to create a TCP client that connects to a server and exchanges data asynchronously. It handles connection, reading, writing, and error events using the nio library. The client sends messages and echoes responses, closing the connection after a specified number of messages or on error. ```cpp #include #include #include #include "nio/nio_event.hpp" #include "nio/client_socket.hpp" using namespace nio; static long long message_count = 0; static const long long total_messages = 10000; static bool connect_server(nio_event &ev, const char *ip, int port) { auto *cli = new client_socket(ev); (*cli).on_connect([cli](socket_t fd, bool expired) { if (fd == -1 || expired) { printf("Connect failed: %s\n", expired ? "timeout" : "error"); cli->close_await(); return; } printf("Connected successfully, fd %d\n", fd); const char *msg = "Hello, server!\n"; if (cli->write(msg, strlen(msg), 5000) == -1) { cli->close_await(); } else { cli->read_await(5000); } }).on_read([cli](socket_t fd, bool expired) { if (expired) { printf("Read timeout\n"); cli->close_await(); return; } char buf[4096]; ssize_t ret = cli->read(buf, sizeof(buf)); if (ret <= 0 || ++message_count >= total_messages) { cli->close_await(); } else { // Echo back if (cli->write(buf, ret, 5000) == -1) { cli->close_await(); } } }).on_error([cli](socket_t fd) { printf("Socket error on fd %d\n", fd); cli->close_await(); }).on_close([cli](socket_t fd) { printf("Connection closed, fd %d\n", fd); delete cli; return true; }); // Initiate async connection with 5 second timeout if (!cli->connect_await(ip, port, 5000)) { delete cli; return false; } return true; } int main() { signal(SIGPIPE, SIG_IGN); nio_event ev(102400, NIO_EVENT_T_KERNEL); if (!connect_server(ev, "127.0.0.1", 8288)) { printf("Failed to connect\n"); return 1; } while (true) { ev.wait(1000); } return 0; } ``` -------------------------------- ### C++: Socket Configuration for Non-blocking and TCP Options Source: https://context7.com/acl-dev/libnio/llms.txt This C++ snippet demonstrates configuring a client socket for non-blocking operations and enabling TCP_NODELAY using libnio's C++ API. It shows how to set up event handlers for connection, data reception, and closure. The code connects to a specified IP and port, then proceeds with I/O after successful configuration. It requires libnio's C++ headers. ```cpp #include "nio/nio_event.hpp" #include "nio/client_socket.hpp" using namespace nio; void configure_socket(nio_event &ev, const char *ip, int port) { auto *cli = new client_socket(ev); (*cli).on_connect([cli](socket_t fd, bool expired) { if (fd == -1 || expired) { cli->close_await(); return; } // Sockets are already non-blocking by default // But you can manually configure if needed nio_event::set_nblock(fd, true); // Enable non-blocking nio_event::set_ndelay(fd, true); // Enable TCP_NODELAY (disable Nagle) printf("Socket %d configured: non-blocking + TCP_NODELAY\n", fd); // Proceed with I/O operations const char *msg = "Data\n"; cli->write(msg, strlen(msg), 5000); cli->read_await(5000); }).on_close([cli](socket_t fd) { delete cli; return true; }); cli->connect_await(ip, port, 5000); } int main() { nio_event ev(10240, NIO_EVENT_T_KERNEL); configure_socket(ev, "127.0.0.1", 8288); while (true) { ev.wait(1000); } return 0; } ``` -------------------------------- ### CMake: Compiler Flags and Library Definitions Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/mqtt/mqtt_server/CMakeLists.txt This snippet defines a comprehensive set of compiler flags for debugging, warnings, and C++ standard compliance. It also defines variables for the paths to static libraries 'libnio.a' and 'libnio_cpp.a'. ```cmake #SET(CMAKE_VERBOSE_MAKEFILE on) add_definitions( "-g" "-W" "-Wall" "-Werror" "-Wshadow" "-Wformat" "-Wpointer-arith" "-D_REENTRANT" "-Wno-long-long" "-Wuninitialized" "-D_POSIX_PTHREAD_SEMANTICS" "-fexceptions" "-Wno-unused-parameter" "-Wno-error=deprecated-declarations" "-Wno-deprecated-declarations" "-fPIC" "-O3" "-std=c++11" ) set(libnio ${home_path}/c/lib/libnio.a) set(libnio_cpp ${home_path}/cpp/lib/libnio_cpp.a) ``` -------------------------------- ### CMake Library Linking Configuration for Client Executable Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/client/CMakeLists.txt Defines the static libraries to be linked and sets up the output directory for the executable. It then creates the 'client' executable and links it against the collected libraries and system dependencies. ```cmake set(libnio ${home_path}/c/lib/libnio.a) set(libnio_cpp ${home_path}/cpp/lib/libnio_cpp.a) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) endif() set(output_path ${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${output_path}) link_directories(${output_path}) add_executable(client ${src_files}) target_link_libraries(client ${lib_all}) ``` -------------------------------- ### CMake Executable Creation and Linking Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/server/CMakeLists.txt This snippet defines the main executable target 'server' using the collected source files ('src_files'). It then links this executable against a list of libraries, including 'libnio_cpp', 'libnio', and system libraries like 'pthread' and 'dl'. The library paths are also configured. ```cmake set(libnio ${home_path}/c/lib/libnio.a) set(libnio_cpp ${home_path}/cpp/lib/libnio_cpp.a) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) endif() set(output_path ${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${output_path}) link_directories(${output_path}) add_executable(server ${src_files}) target_link_libraries(server ${lib_all}) ``` -------------------------------- ### CMake: Library Path and Linking Configuration Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/timer/CMakeLists.txt Specifies the paths to static libraries ('libnio.a' and 'libnio_cpp.a') and configures the linker to use these libraries along with pthread and dl for both Darwin and Linux. It also sets the runtime output directory. ```cmake set(libnio ${home_path}/c/lib/libnio.a) set(libnio_cpp ${home_path}/cpp/lib/libnio_cpp.a) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) endif() set(output_path ${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${output_path}) link_directories(${output_path}) ``` -------------------------------- ### CMake: Project Initialization and Build Type Check Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/client2/CMakeLists.txt Initializes the CMake project, sets the project name to 'client2', and checks the build type (RELEASE, DEBUG, or default). It enforces building in a separate directory to avoid conflicts. Compiler status messages are displayed based on the build type. ```cmake cmake_minimum_required(VERSION 3.2.0) project(client2) if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") message(STATUS "build clientf release version") elseif (CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(STATUS "build client2 for debug version") else() message(STATUS "build client2 for default version") endif() ``` -------------------------------- ### CMake: Project Initialization and Build Type Configuration Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/timer/CMakeLists.txt Initializes the CMake project, sets the project name, and configures build behavior based on the CMAKE_BUILD_TYPE. It includes checks to prevent building in the source directory and provides status messages for release, debug, or default builds. ```cmake cmake_minimum_required(VERSION 3.2.0) project(timer) if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") message(STATUS "build aio_server for release version") elseif (CMAKE_BUILD_TYPE STREQUAL "DEBUG") message(STATUS "build aio_server for debug version") else() message(STATUS "build aio_server for default version") endif() ``` -------------------------------- ### CMake System-Specific Configuration (Darwin/Linux) Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/server/CMakeLists.txt This section configures build settings based on the detected operating system (Darwin or Linux). For Darwin, it includes specific include directories and custom archive creation/finish commands. For Linux, it's currently a placeholder. An error is raised for unknown systems. ```cmake if(CMAKE_SYSTEM_NAME MATCHES "Darwin") add_definitions("-Wno-invalid-source-encoding") include_directories("/usr/local/include") SET(CMAKE_CXX_ARCHIVE_CREATE " Scr ") SET(CMAKE_CXX_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") else() message(FATAL_ERROR "unknown CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}") endif() ``` -------------------------------- ### CMake: Executable Definition and Linking Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/client2/CMakeLists.txt Sets the output directory for runtime artifacts and defines the main executable 'client2' using the collected source files. It then links the executable against the system-dependent list of libraries defined in 'lib_all'. ```cmake set(output_path ${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${output_path}) link_directories(${output_path}) add_executable(client2 ${src_files}) target_link_libraries(client2 ${lib_all}) ``` -------------------------------- ### CMake: Source Directory and Include Path Configuration Source: https://github.com/acl-dev/libnio/blob/main/cpp/CMakeLists.txt Defines the source directories for the library and sets the include directories. This ensures that the compiler can find header files located in the src, include, and a relative ../c/src directory. ```cmake set(src ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/mqtt ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/../c/src ) ``` -------------------------------- ### CMake: Platform-Specific Configuration Source: https://github.com/acl-dev/libnio/blob/main/CMakeLists.txt Configures build settings based on the detected CMAKE_SYSTEM_NAME. Includes setting include and link directories, linker flags, and runtime paths for FreeBSD, and RPATH for macOS. Handles unknown system names with a fatal error. ```cmake cmake_minimum_required(VERSION 3.2.0) project(libnio) if (${CMAKE_BINARY_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) message(FATAL_ERROR "Please into another dir to build!") endif() #string(TOUPPER ${CMAKE_SYSTEM_NAME} CMAKE_SYSTEM_NAME) if (CMAKE_SYSTEM_NAME MATCHES "Android") message(STATUS "current platform: Android") message(STATUS "current ndk path: ${CMAKE_ANDROID_NDK}") elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") message(STATUS "current platform: Linux") elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") message(STATUS "current platform: Darwin") set(CMAKE_MACOSX_RPATH build) elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") message(STATUS "current platform: FreeBSD") include_directories( #/usr/include/c++/4.2 #/usr/include/c++/4.2/backward /usr/include /usr/local/include ) link_directories( /usr/lib /usr/local/lib ) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--export-dynamic") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,./:./lib:../:../lib") elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") message(STATUS "current platform: Windows") else() message(FATAL_ERROR "unknown CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}") endif() if (CMAKE_SYSTEM_NAME MATCHES "Darwin") set(CMAKE_MACOSX_RPATH build) endif() ``` -------------------------------- ### CMake: Executable Target and Linking Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/server2/CMakeLists.txt Defines the 'server2' executable using the discovered source files and links the previously defined set of libraries to it. It also sets the runtime output directory for the executable. ```cmake add_executable(server2 ${src_files}) target_link_libraries(server2 ${lib_all}) ``` -------------------------------- ### CMake: Executable Target and Linking Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/timer/CMakeLists.txt Defines the main executable target named 'timer' using the collected source files and links it with the pre-defined set of libraries. ```cmake add_executable(timer ${src_files}) target_link_libraries(timer ${lib_all}) ``` -------------------------------- ### CMake Source Directory Compilation Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/server/CMakeLists.txt This snippet defines source directory paths and then iterates through them to collect all source files into a list named 'src_files'. The 'aux_source_directory' command is used for this purpose. This is a common pattern for gathering source files dynamically. ```cmake set(base_path ${CMAKE_CURRENT_SOURCE_DIR}) set(src_paths ${base_path}) foreach(iter ${src_paths}) aux_source_directory(${iter} src_files) endforeach() ``` -------------------------------- ### CMake Compiler Definitions and Flags Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/server/CMakeLists.txt This section sets a comprehensive list of preprocessor definitions and compiler flags for the build. These flags include debugging symbols, various warning levels, reentrancy definitions, exception handling, optimization levels, and C++ standard specification. ```cmake add_definitions( "-g" "-W" "-Wall" "-Werror" "-Wshadow" "-Wformat" "-Wpointer-arith" "-D_REENTRANT" "-Wno-long-long" "-Wuninitialized" "-D_POSIX_PTHREAD_SEMANTICS" "-fexceptions" "-Wno-unused-parameter" "-Wno-error=deprecated-declarations" "-Wno-deprecated-declarations" "-fPIC" "-O3" "-Wno-error=unused-result" "-std=c++11" ) ``` -------------------------------- ### CMake: Compiler Flags and Library Definitions Source: https://github.com/acl-dev/libnio/blob/main/samples-c++/client2/CMakeLists.txt Defines a comprehensive set of compiler flags, including debug symbols, warning levels, error handling, and C++ standard. It also defines paths to static libraries 'libnio.a' and 'libnio_cpp.a', and sets up a system-dependent list 'lib_all' for linking. ```cmake #SET(CMAKE_VERBOSE_MAKEFILE on) add_definitions( "-g" "-W" "-Wall" "-Werror" "-Wshadow" "-Wformat" "-Wpointer-arith" "-D_REENTRANT" "-Wno-long-long" "-Wuninitialized" "-D_POSIX_PTHREAD_SEMANTICS" "-fexceptions" "-Wno-unused-parameter" "-Wno-error=deprecated-declarations" "-Wno-deprecated-declarations" "-fPIC" "-O3" "-std=c++11" ) set(libnio ${home_path}/c/lib/libnio.a) set(libnio_cpp ${home_path}/cpp/lib/libnio_cpp.a) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(lib_all ${libnio_cpp} ${libnio} -lpthread -ldl) endif() ```