...
This commit is contained in:
@@ -5,6 +5,12 @@ option(SNPLIB_BUILD_EXAMPLES "Build examples" ON)
|
||||
|
||||
option(SNPLIB_USE_SPDLOG "Use of spdlog library" ON)
|
||||
|
||||
option(
|
||||
SNPLIB_USE_ASIO
|
||||
"add network related implementation using ASIO library"
|
||||
ON
|
||||
)
|
||||
|
||||
if(SNPLIB_USE_SPDLOG)
|
||||
include(FetchContent)
|
||||
# find_package(spdlog CONFIG)
|
||||
@@ -45,8 +51,47 @@ set(LIB_HEADERS
|
||||
include/snipplib/containers/snplib_hvec.h
|
||||
include/snipplib/serialization/snplib_serialization.h
|
||||
include/snipplib/network/snplib_endpoint.h
|
||||
include/snipplib/network/snplib_network.h
|
||||
)
|
||||
|
||||
if(SNPLIB_USE_ASIO)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(ASIOLIB IMPORTED_TARGET GLOBAL asio)
|
||||
|
||||
if(NOT ASIOLIB_FOUND)
|
||||
message(STATUS "\tfetch asio-lib ...")
|
||||
|
||||
FetchContent_Declare(
|
||||
asiolib_project
|
||||
PREFIX
|
||||
${CMAKE_BINARY_DIR}/asio
|
||||
GIT_REPOSITORY "https://github.com/chriskohlhoff/asio.git"
|
||||
GIT_TAG "asio-1-38-0"
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(asiolib_project)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${asiolib_project_SOURCE_DIR}/asio
|
||||
COMMAND ./autogen.sh
|
||||
)
|
||||
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${asiolib_project_SOURCE_DIR}/asio
|
||||
COMMAND ./configure --prefix=${asiolib_project_SOURCE_DIR}/asio
|
||||
)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} "${asiolib_project_SOURCE_DIR}/asio")
|
||||
pkg_check_modules(ASIOLIB IMPORTED_TARGET GLOBAL asio)
|
||||
|
||||
message(STATUS "ASIO INC PATHS: ${ASIOLIB_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
list(APPEND LIB_HEADERS include/snipplib/network/snplib_network_asio.h)
|
||||
endif(SNPLIB_USE_ASIO)
|
||||
|
||||
add_library(${PROJECT_NAME} INTERFACE ${LIB_HEADERS})
|
||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_23)
|
||||
target_include_directories(
|
||||
@@ -55,6 +100,9 @@ target_include_directories(
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
|
||||
)
|
||||
|
||||
# add dependencies
|
||||
|
||||
if(SNPLIB_USE_SPDLOG)
|
||||
target_compile_definitions(
|
||||
${PROJECT_NAME}
|
||||
@@ -64,7 +112,11 @@ if(SNPLIB_USE_SPDLOG)
|
||||
SNPLIB_SPDLOGGER=1
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE spdlog::spdlog_header_only)
|
||||
endif()
|
||||
endif(SNPLIB_USE_SPDLOG)
|
||||
|
||||
if(SNPLIB_USE_ASIO)
|
||||
target_link_libraries(${PROJECT_NAME} INTERFACE PkgConfig::ASIOLIB)
|
||||
endif(SNPLIB_USE_ASIO)
|
||||
|
||||
if(SNPLIB_BUILD_EXAMPLES)
|
||||
set(EXAM_STRING str_exam)
|
||||
|
||||
@@ -17,7 +17,7 @@ int main()
|
||||
|
||||
std::println("BYTES VEC: {}", bytes_vec);
|
||||
|
||||
auto msg = proto.fromBytes(bytes_vec);
|
||||
auto msg = proto.fromTransport(bytes_vec);
|
||||
|
||||
if (msg) {
|
||||
std::println("MSG (from std::vector): {}", msg.value());
|
||||
@@ -25,7 +25,7 @@ int main()
|
||||
std::println("MSG ERR: {}", msg.error().message());
|
||||
}
|
||||
|
||||
auto msg_l = proto.fromBytes(bytes_lst);
|
||||
auto msg_l = proto.fromTransport(bytes_lst);
|
||||
|
||||
if (msg_l) {
|
||||
std::println("MSG (from std::list): {}", msg_l.value());
|
||||
@@ -33,7 +33,7 @@ int main()
|
||||
std::println("MSG ERR: {}", msg_l.error().message());
|
||||
}
|
||||
|
||||
auto vmsg = proto.fromBytes<std::vector<char>>(bytes_lst);
|
||||
auto vmsg = proto.fromTransport<std::vector<char>>(bytes_lst);
|
||||
if (vmsg) {
|
||||
std::println("VMSG (from std::list): {}", vmsg.value());
|
||||
} else {
|
||||
@@ -49,13 +49,13 @@ int main()
|
||||
|
||||
std::println("MSG: {}", bytes_vec);
|
||||
|
||||
auto bs = proto.toBytes(bytes_vec);
|
||||
auto bs = proto.toTransport(bytes_vec);
|
||||
std::println("BYTES (from std::vector): {}", bs);
|
||||
|
||||
auto bs1 = proto.toBytes(bytes_lst);
|
||||
auto bs1 = proto.toTransport(bytes_lst);
|
||||
std::println("BYTES (from std::list): {}", bs1);
|
||||
|
||||
bytes_vec = proto.toBytes<decltype(bytes_vec)>(bytes_lst);
|
||||
bytes_vec = proto.toTransport<decltype(bytes_vec)>(bytes_lst);
|
||||
std::println("BYTES: {}", bytes_vec);
|
||||
|
||||
|
||||
@@ -71,24 +71,24 @@ int main()
|
||||
|
||||
std::println("BLOB: {}", bytes);
|
||||
|
||||
bs = bb_proto.toBytes(bytes_vec);
|
||||
bs = bb_proto.toTransport(bytes_vec);
|
||||
std::println("BYTES (from std::vector): {}", bs);
|
||||
|
||||
auto bs2 = bb_proto.toBytes(bytes_lst);
|
||||
auto bs2 = bb_proto.toTransport(bytes_lst);
|
||||
std::println("BYTES (from std::list): {}", bs2);
|
||||
|
||||
auto blob = std::vector(std::from_range, bs | std::views::join);
|
||||
|
||||
std::println("\nBYTES: {}", blob);
|
||||
|
||||
vmsg = bb_proto.fromBytes<std::vector<char>>(blob);
|
||||
vmsg = bb_proto.fromTransport<std::vector<char>>(blob);
|
||||
if (vmsg) {
|
||||
std::println("BLOB (from std::vector): {}", vmsg.value());
|
||||
} else {
|
||||
std::println("VMSG ERR: {}", vmsg.error().message());
|
||||
}
|
||||
|
||||
// std::array<char, 30> arr = bb_proto.toBytes<decltype(arr)>(bytes_lst);
|
||||
// std::array<char, 30> arr = bb_proto.toTransport<decltype(arr)>(bytes_lst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <expected>
|
||||
#include <ranges>
|
||||
|
||||
|
||||
#include <asio/awaitable.hpp>
|
||||
|
||||
namespace snplib
|
||||
{
|
||||
|
||||
@@ -194,12 +197,22 @@ concept ret_expected_type_c = requires {
|
||||
|
||||
// result of asynchronous callable
|
||||
|
||||
template <typename, typename = std::void_t<>>
|
||||
struct has_co_await_operator : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_co_await_operator<T, std::void_t<decltype(std::declval<T>().operator co_await())>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool has_co_await_operator_v = has_co_await_operator<T>::value;
|
||||
|
||||
|
||||
template <typename T, typename UT = void>
|
||||
concept result_awaiter_c = requires(T t, std::coroutine_handle<> hndl) {
|
||||
{ t.await_ready() } -> std::convertible_to<bool>;
|
||||
|
||||
// await_suspend can return void, bool, or a coroutine_handle
|
||||
t.await_suspend(hndl);
|
||||
// t.await_suspend(hndl);
|
||||
|
||||
// await_resume must return the specific type UT
|
||||
{ t.await_resume() } -> std::same_as<UT>;
|
||||
@@ -207,13 +220,37 @@ concept result_awaiter_c = requires(T t, std::coroutine_handle<> hndl) {
|
||||
|
||||
|
||||
template <typename T, typename UT = void>
|
||||
concept result_awaitable_c = result_awaiter_c<T, UT> || requires(T t) {
|
||||
{ t.operator co_await() } -> result_awaiter_c<UT>;
|
||||
concept result_awaitable_c = requires(T t) {
|
||||
// { t.operator co_await() } -> result_awaiter_c<UT>;
|
||||
t.operator co_await();
|
||||
};
|
||||
// template <typename T, typename UT = void>
|
||||
// concept result_awaitable_c = result_awaiter_c<T, UT> || requires(T t) {
|
||||
// { t.operator co_await() } -> result_awaiter_c<UT>;
|
||||
// };
|
||||
|
||||
template <typename T, typename RT = void>
|
||||
concept awaitable_type_c =
|
||||
(!has_co_await_operator_v<T> ||
|
||||
std::same_as<decltype(std::declval<decltype(std::declval<T>().operator co_await())>().await_resume()), RT>) &&
|
||||
(has_co_await_operator_v<T> || std::same_as<decltype(std::declval<T>().await_resume()), RT>);
|
||||
|
||||
|
||||
static_assert(awaitable_type_c<asio::awaitable<void>>, "!!!");
|
||||
|
||||
template <typename T, typename UT = void>
|
||||
concept async_retval_c = result_awaitable_c<T, UT> && ret_expected_c<UT>;
|
||||
concept async_retval_c = result_awaitable_c<decltype(std::declval<T>().operator co_await())> || requires {
|
||||
[] -> auto {
|
||||
T t;
|
||||
co_await t;
|
||||
}();
|
||||
};
|
||||
// template <typename T, typename UT = void>
|
||||
// concept async_retval_c = result_awaiter_c<decltype(std::declval<T>().operator co_await()), UT>;
|
||||
|
||||
// template <typename T, typename UT = void>
|
||||
// concept async_retval_c = result_awaitable_c<T, UT> && ret_expected_c<UT>;
|
||||
}; // namespace snplib
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ struct netproto_stopseq_t {
|
||||
// returns 2-element range of the input messsage and stop-sequence
|
||||
template <std::ranges::range OR, input_char_range_c IR>
|
||||
requires char_range_c<std::ranges::range_value_t<OR>> // range of char ranges
|
||||
OR toBytes(IR&& message)
|
||||
OR toTransport(IR&& message)
|
||||
{
|
||||
OR res;
|
||||
|
||||
@@ -45,7 +45,7 @@ struct netproto_stopseq_t {
|
||||
|
||||
// returns a copy of the input message + tralling stop-sequence
|
||||
template <output_char_range_c OR, input_char_range_c IR>
|
||||
OR toBytes(IR&& message)
|
||||
OR toTransport(IR&& message)
|
||||
{
|
||||
OR res;
|
||||
|
||||
@@ -56,7 +56,7 @@ struct netproto_stopseq_t {
|
||||
}
|
||||
|
||||
template <input_char_range_c IR>
|
||||
auto toBytes(IR&& message)
|
||||
auto toTransport(IR&& message)
|
||||
{
|
||||
if constexpr (std::ranges::contiguous_range<IR>) {
|
||||
return std::array{std::span<const char>{message}, std::span<const char>{NETPROTO_STOP_SEQ}};
|
||||
@@ -67,7 +67,7 @@ struct netproto_stopseq_t {
|
||||
}
|
||||
|
||||
template <std::ranges::range OR, input_char_range_c IR>
|
||||
std::expected<OR, std::error_code> fromBytes(IR&& bytes)
|
||||
std::expected<OR, std::error_code> fromTransport(IR&& bytes)
|
||||
{
|
||||
auto found = std::ranges::search(std::forward<IR>(bytes), NETPROTO_STOP_SEQ);
|
||||
if (found.empty()) {
|
||||
@@ -122,22 +122,22 @@ struct netproto_stopseq_t {
|
||||
|
||||
// deduces a view-type from the input range-type
|
||||
template <typename IR>
|
||||
auto fromBytes(IR&& bytes)
|
||||
auto fromTransport(IR&& bytes)
|
||||
requires input_char_range_c<std::remove_cvref_t<IR>>
|
||||
{
|
||||
using or_t =
|
||||
std::conditional_t<std::ranges::contiguous_range<IR>, std::span<const char>,
|
||||
std::ranges::subrange<std::ranges::iterator_t<IR>, std::ranges::sentinel_t<IR>>>;
|
||||
|
||||
return fromBytes<or_t>(std::forward<IR>(bytes));
|
||||
return fromTransport<or_t>(std::forward<IR>(bytes));
|
||||
}
|
||||
|
||||
// to satisfy 'net_proto_c' concept
|
||||
template <typename CharT = char>
|
||||
requires(std::same_as<CharT, char> || std::same_as<CharT, const char>)
|
||||
std::expected<std::span<CharT>, std::error_code> fromBytes(std::span<CharT> bytes)
|
||||
std::expected<std::span<CharT>, std::error_code> fromTransport(std::span<CharT> bytes)
|
||||
{
|
||||
return fromBytes<std::span<CharT>>(bytes);
|
||||
return fromTransport<std::span<CharT>>(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -148,11 +148,11 @@ static_assert(net_proto_c<netproto_stopseq_t<>>, "!!!");
|
||||
/* BINARY BLOB PROTOCOL */
|
||||
|
||||
/*
|
||||
* a sequence of bytes in format:
|
||||
* <blob size field><binary blob bytes>
|
||||
*
|
||||
blob size field: a symbolic representation of a HEXIMAL UNSIGNED INTEGER (e.g. "000000FA", MUST BE IN
|
||||
UPPER-CASE!!!)
|
||||
a sequence of bytes in format:
|
||||
<blob size field><binary blob bytes>
|
||||
|
||||
blob size field: a symbolic representation of a HEXIMAL UNSIGNED INTEGER
|
||||
(e.g. "000000FA", MUST BE IN UPPER-CASE!!!)
|
||||
*/
|
||||
|
||||
template <size_t SZ_FIELD_WIDTH = 8>
|
||||
@@ -164,7 +164,7 @@ struct netproto_binary_blob_t {
|
||||
static constexpr std::array<char, 6> BLOB_SIZE_FIELD_FORMAT{'{', ':', '0', '0' + BLOB_SIZE_FIELD, 'X', '}'};
|
||||
|
||||
template <input_char_range_c IR>
|
||||
auto toBytes(IR&& message)
|
||||
auto toTransport(IR&& message)
|
||||
{
|
||||
static thread_local std::string Nbytes{};
|
||||
|
||||
@@ -182,7 +182,7 @@ struct netproto_binary_blob_t {
|
||||
|
||||
|
||||
template <char_range_c OR, input_char_range_c IR>
|
||||
std::expected<OR, std::error_code> fromBytes(IR&& bytes)
|
||||
std::expected<OR, std::error_code> fromTransport(IR&& bytes)
|
||||
{
|
||||
using inp_t = std::remove_cvref_t<IR>;
|
||||
|
||||
@@ -255,6 +255,32 @@ struct netproto_binary_blob_t {
|
||||
static_assert(false, "Unsupported output byte sequence type!");
|
||||
}
|
||||
}
|
||||
|
||||
// deduces a view-type from the input range-type
|
||||
template <typename IR>
|
||||
auto fromTransport(IR&& bytes)
|
||||
requires input_char_range_c<std::remove_cvref_t<IR>>
|
||||
{
|
||||
using or_t =
|
||||
std::conditional_t<std::ranges::contiguous_range<IR>, std::span<const char>,
|
||||
std::ranges::subrange<std::ranges::iterator_t<IR>, std::ranges::sentinel_t<IR>>>;
|
||||
|
||||
return fromTransport<or_t>(std::forward<IR>(bytes));
|
||||
}
|
||||
|
||||
// to satisfy 'net_proto_c' concept
|
||||
template <typename CharT = char>
|
||||
requires(std::same_as<CharT, char> || std::same_as<CharT, const char>)
|
||||
std::expected<std::span<CharT>, std::error_code> fromTransport(std::span<CharT> bytes)
|
||||
{
|
||||
return fromTransport<std::span<CharT>>(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static_assert(net_proto_c<netproto_binary_blob_t<>>, "!!!");
|
||||
|
||||
|
||||
|
||||
} // namespace snplib
|
||||
@@ -12,7 +12,7 @@ namespace snplib
|
||||
template <typename T>
|
||||
concept net_endpoint_c = requires(T t, const T t_const) {
|
||||
// static constexpr member
|
||||
std::formattable<decltype(T::id), char>;
|
||||
requires std::formattable<decltype(T::id), char>;
|
||||
[]() { [[maybe_unused]] static constexpr auto val = T::id; }();
|
||||
|
||||
{ t.endpoint() } -> char_range_c;
|
||||
@@ -27,21 +27,19 @@ concept net_endpoint_c = requires(T t, const T t_const) {
|
||||
template <typename T, typename CharRangeT = std::vector<char>>
|
||||
concept net_proto_c = requires(T t) {
|
||||
// from session-level representation to transport-level one
|
||||
{ t.toBytes(std::declval<CharRangeT>()) } -> char_range_or_range_of_char_ranges_c;
|
||||
{ t.toTransport(std::declval<CharRangeT>()) } -> char_range_or_range_of_char_ranges_c;
|
||||
|
||||
// from transport-level representation to session-level one
|
||||
requires(
|
||||
requires {
|
||||
// { t.fromBytes(std::declval<std::span<const char>>()) } -> char_range_c;
|
||||
{ t.fromBytes(std::declval<std::span<const char>>()) } -> ret_expected_c;
|
||||
{ t.fromTransport(std::declval<std::span<const char>>()) } -> ret_expected_c;
|
||||
requires char_range_c<std::remove_cvref_t<
|
||||
decltype(std::declval<T>().fromBytes(std::declval<std::span<const char>>()).value())>>;
|
||||
decltype(std::declval<T>().fromTransport(std::declval<std::span<const char>>()).value())>>;
|
||||
} ||
|
||||
requires {
|
||||
// { t.fromBytes(std::declval<std::span<char>>()) } -> char_range_c;
|
||||
{ t.fromBytes(std::declval<std::span<char>>()) } -> ret_expected_c;
|
||||
requires char_range_c<
|
||||
std::remove_cvref_t<decltype(std::declval<T>().fromBytes(std::declval<std::span<char>>()).value())>>;
|
||||
{ t.fromTransport(std::declval<std::span<char>>()) } -> ret_expected_c;
|
||||
requires char_range_c<std::remove_cvref_t<
|
||||
decltype(std::declval<T>().fromTransport(std::declval<std::span<char>>()).value())>>;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -66,13 +64,21 @@ concept net_message_c = requires(const T t_const) {
|
||||
template <typename T>
|
||||
concept net_connection_c = requires(T t) {
|
||||
// static constexpr member
|
||||
std::formattable<decltype(T::id), char>;
|
||||
requires std::formattable<decltype(T::id), char>;
|
||||
[]() { [[maybe_unused]] static constexpr auto val = T::id; }();
|
||||
|
||||
typename T::message_t; // minimal allowed unit of read/write operations
|
||||
typename T::error_t;
|
||||
|
||||
{ t.send(std::declval<typename T::message_t>()) } -> async_retval_c;
|
||||
{ t.recv() } -> async_retval_c<typename T::message_t>;
|
||||
// { t.send(std::declval<typename T::message_t>()) } -> async_retval_c<typename T::error_t>;
|
||||
{ t.send(std::declval<typename T::message_t>()) } -> awaitable_type_c<typename T::error_t>;
|
||||
// { t.recv() } -> async_retval_c<typename T::message_t>;
|
||||
{ t.recv() } -> awaitable_type_c<typename T::message_t>;
|
||||
|
||||
// [] {
|
||||
// typename T::message_t msg;
|
||||
// co_await t.send(msg);
|
||||
// }();
|
||||
|
||||
t.close();
|
||||
};
|
||||
@@ -85,7 +91,7 @@ concept net_session_c =
|
||||
typename T::ident_t;
|
||||
typename T::context_t;
|
||||
|
||||
net_connection_c<typename T::connection_t>;
|
||||
requires net_connection_c<typename T::connection_t>;
|
||||
|
||||
{ t_const.ident() } -> std::same_as<typename T::ident_t>;
|
||||
|
||||
@@ -104,10 +110,10 @@ concept net_session_c =
|
||||
template <typename T>
|
||||
concept net_listener_c = requires(T t, const T t_const) {
|
||||
// static constexpr member
|
||||
std::formattable<decltype(T::id), char>;
|
||||
requires std::formattable<decltype(T::id), char>;
|
||||
[]() { [[maybe_unused]] static constexpr auto val = T::id; }();
|
||||
|
||||
net_connection_c<typename T::connection_t>;
|
||||
requires net_connection_c<typename T::connection_t>;
|
||||
|
||||
{ t.accept() } -> async_retval_c<typename T::connection_t>;
|
||||
|
||||
@@ -144,7 +150,7 @@ concept net_initiator_c =
|
||||
// to be sure 'ROLE' is compile-time constant
|
||||
[]() { [[maybe_unused]] static constexpr auto val = T::ROLE; }();
|
||||
|
||||
net_connection_c<typename T::connection_t>;
|
||||
requires net_connection_c<typename T::connection_t>;
|
||||
|
||||
{ t_const.endpoint() } -> net_endpoint_c;
|
||||
} && ((T::ROLE != decltype(T::ROLE)::ROLE_SERVER) || requires(T t) { // use of short-circuiting logic!!!
|
||||
@@ -165,7 +171,7 @@ concept net_initiator_c =
|
||||
template <typename T>
|
||||
concept netserver_c = requires(T t) {
|
||||
// static constexpr member
|
||||
std::formattable<decltype(T::id), char>;
|
||||
requires std::formattable<decltype(T::id), char>;
|
||||
[]() { [[maybe_unused]] static constexpr auto val = T::id; }();
|
||||
|
||||
|
||||
|
||||
55
include/snipplib/network/snplib_network_asio.h
Normal file
55
include/snipplib/network/snplib_network_asio.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <asio/buffer.hpp>
|
||||
#include <asio/experimental/coro.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/use_awaitable.hpp>
|
||||
#include <asio/write.hpp>
|
||||
|
||||
#include "snplib_netmsg.h"
|
||||
#include "snplib_netproto.h"
|
||||
#include "snplib_network.h"
|
||||
|
||||
namespace snplib::asio
|
||||
{
|
||||
template <net_message_c NETMSG_T, net_proto_c NETPROTO_T>
|
||||
class asio_net_connection_t
|
||||
{
|
||||
public:
|
||||
typedef NETMSG_T message_t;
|
||||
typedef NETPROTO_T netproto_t;
|
||||
|
||||
typedef std::error_code error_t;
|
||||
typedef std::expected<message_t, error_t> result_t;
|
||||
|
||||
static constexpr std::string_view id{"ASIO-NETCONN"};
|
||||
|
||||
// ::asio::awaitable<void> send(asio_net_connection_t::message_t msg)
|
||||
// {
|
||||
// char data[1024];
|
||||
// size_t n = 1024;
|
||||
|
||||
// auto executor = co_await ::asio::this_coro::executor;
|
||||
// ::asio::ip::tcp::acceptor acceptor(executor, {::asio::ip::tcp::v4(), 55555});
|
||||
|
||||
// ::asio::ip::tcp::socket socket = co_await acceptor.async_accept(::asio::use_awaitable);
|
||||
|
||||
// co_await ::asio::async_write(socket, ::asio::buffer(data, n), ::asio::use_awaitable);
|
||||
// }
|
||||
|
||||
// ::asio::awaitable<void> recv() {}
|
||||
|
||||
// ::asio::awaitable<void> close() {}
|
||||
|
||||
// ::asio::experimental::coro<error_t> send(asio_net_connection_t::message_t msg) {}
|
||||
::asio::awaitable<error_t> send(asio_net_connection_t::message_t msg) {}
|
||||
|
||||
::asio::awaitable<message_t> recv() {}
|
||||
|
||||
::asio::awaitable<error_t> close() {}
|
||||
};
|
||||
|
||||
|
||||
static_assert(net_connection_c<asio_net_connection_t<keyval_netmsg_t<>, netproto_stopseq_t<>>>, "!!!");
|
||||
|
||||
} // namespace snplib::asio
|
||||
Reference in New Issue
Block a user