Add asio standalone example (#133)

* Add asio standalone example

* Mark VERSION explicitly

Without this version information, CPM's versioning mechanism may break
in some cases.

Also add comments for compile definition on Windows.

* Use aync-tcp-echo-server as the example

* Add boost software license to the demo source

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>

Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
This commit is contained in:
Kingsley Chen
2020-06-24 18:40:12 +08:00
committed by GitHub
parent 9ec279c75f
commit f8afae6eb3
2 changed files with 197 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(CPMExampleASIOStandalone)
# ---- Dependencies ----
include(../../cmake/CPM.cmake)
find_package(Threads REQUIRED)
CPMAddPackage(
NAME asio
VERSION 1.16.1
GITHUB_REPOSITORY chriskohlhoff/asio
GIT_TAG asio-1-16-1 # asio uses non-standard version tag, we must specify GIT_TAG
)
# ASIO doesn't use CMake, we have to configure it manually.
# Extra notes for using on Windows:
# 1) If _WIN32_WINNT is not set, ASIO assumes _WIN32_WINNT=0x0501, i.e. Windows XP target,
# which is definitely not the platform which most users target.
# 2) WIN32_LEAN_AND_MEAN is defined to make Winsock2 work.
if(asio_ADDED)
add_library(asio INTERFACE)
target_include_directories(asio
INTERFACE ${asio_SOURCE_DIR}/asio/include
)
target_compile_definitions(asio
INTERFACE
ASIO_STANDALONE
ASIO_NO_DEPRECATED
)
target_link_libraries(asio
INTERFACE
Threads::Threads
)
if(WIN32)
# macro see @ https://stackoverflow.com/a/40217291/1746503
macro(get_win32_winnt version)
if (CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION})
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
if ("${verMajor}" MATCHES "10")
set(verMajor "A")
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
endif ("${verMajor}" MATCHES "10")
# Remove all remaining '.' characters.
string(REPLACE "." "" ver ${ver})
# Prepend each digit with a zero.
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
set(${version} "0x${ver}")
endif()
endmacro()
if(NOT DEFINED _WIN32_WINNT)
get_win32_winnt(ver)
set(_WIN32_WINNT ${ver})
endif()
message(STATUS "Set _WIN32_WINNET=${_WIN32_WINNT}")
target_compile_definitions(asio
INTERFACE
_WIN32_WINNT=${_WIN32_WINNT}
WIN32_LEAN_AND_MEAN
)
endif()
endif()
# ---- Executable ----
add_executable(CPMExampleASIOStandalone main.cpp)
target_link_libraries(CPMExampleASIOStandalone asio)

View File

@@ -0,0 +1,118 @@
//
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0.
// (See http://www.boost.org/LICENSE_1_0.txt)
//
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include "asio.hpp"
// An asynchronous tcp echo server.
// See https://think-async.com/Asio/asio-1.16.1/src/examples/cpp11/echo/async_tcp_echo_server.cpp
using asio::ip::tcp;
class session
: public std::enable_shared_from_this<session>
{
public:
session(tcp::socket socket)
: socket_(std::move(socket))
{
}
void start()
{
do_read();
}
private:
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(asio::buffer(data_, max_length),
[this, self](std::error_code ec, std::size_t length)
{
if (!ec)
{
do_write(length);
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(socket_, asio::buffer(data_, length),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
do_read();
}
});
}
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
class server
{
public:
server(asio::io_context& io_context, short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
{
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(
[this](std::error_code ec, tcp::socket socket)
{
if (!ec)
{
std::make_shared<session>(std::move(socket))->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: async_tcp_echo_server <port>\n";
return 1;
}
asio::io_context io_context;
server s(io_context, std::atoi(argv[1]));
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}