Boost.Asio

# Makefile for top dir
# $(call makever,1.2.3)
# major.minor.patch
# libtool manual: -version-number
define makever
? @ $(MAKE) -C $@ soname=lib$@.so.$(word 1,$(subst ., ,$(1)))
? @ cp $(OBJDIR)/$@/$@ $(OBJDIR)/$@/lib$@.so.$(1)
? @ cd $(OBJDIR)/$@ ; \
? ? ln -f -s lib$@.so.$(1) lib$@.so.$(word 1,$(subst ., ,$(1))) ; \
? ? cd - >/dev/null 2>&1 ;
? @ cd $(OBJDIR)/$@ ; \
? ? ln -f -s lib$@.so.$(1) lib$@.so ; \
? ? cd - >/dev/null 2>&1 ;
endef
# make # BUILD_DIR=build
ifdef BUILD_DIR
export OBJDIR = $(abspath $(BUILD_DIR))
else
export OBJDIR = $(abspath build)
endif
SUBDIRS = main # foo
all : $(SUBDIRS)
install : $(SUBDIRS)
$(SUBDIRS) : | $(OBJDIR)
$(OBJDIR) : ; @ mkdir $@
# main : foo
main : ; @ $(MAKE) -C $@
# foo : ; $(call makever,1.2.3)
# make DESTDIR=~/foo install
# Alexandre Duret-Lutz's Autotools Tutorial (without animations):
# "is ready to be uncompressed in / on many hosts"
install :
? install -d $(DESTDIR)/usr/local/bin
? install -d $(DESTDIR)/usr/local/lib
? install -m 0755 $(OBJDIR)/main/server $(DESTDIR)/usr/local/bin
? install -m 0755 $(OBJDIR)/main/client $(DESTDIR)/usr/local/bin
? # cp -P $(OBJDIR)/foo/*.so* $(DESTDIR)/usr/local/lib
clean :
? @ for dir in $(SUBDIRS); do \
? ? $(MAKE) -C $$dir $@; \
? done
? -rm -fr $(OBJDIR)
.PHONY : $(SUBDIRS) all install clean
---
# Makefile for subdir
# build shared library with -fPIC, -shared
CXXFLAGS ?= # -g -O3 -fPIC # CXXFLAGS for .cpp
CPPFLAGS ?= -MMD -MP -I/home/ljh/Downloads/boost_1_81_0/ # -I../foo
LDFLAGS ? = -L/home/ljh/Downloads/boost_1_81_0/stage/lib # -L$(OBJDIR)/foo # -shared
LDLIBS ? ?= -lpthread
# CC ? ? ?= $(CXX) # link with CXX for .cpp
LDFLAGS ?+= -Wl,-rpath,'$$ORIGIN/../foo'
LDFLAGS ?+= -Wl,-rpath,'$$ORIGIN/../lib'
#LDFLAGS += -Wl,-soname,$(soname)
# make # NDEBUG=1
ifdef NDEBUG
CXXFLAGS += -O3 # .cpp
CPPFLAGS += -DNDEBUG
else
CXXFLAGS += -g # .cpp
LDFLAGS ?+= -fsanitize=address
endif
SUBDIR ? ?= $(OBJDIR)/$(lastword $(subst /, ,$(CURDIR)))
all : $(SUBDIR)/server $(SUBDIR)/client
# https://make.mad-scientist.net/papers/how-not-to-use-vpath/
# $(SUBDIR)/main : $(addprefix $(SUBDIR)/,$(patsubst %.c,%.o,$(wildcard *.c))) # .cpp
# ? $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
$(SUBDIR)/server : $(addprefix $(SUBDIR)/,$(patsubst %.cpp,%.o,server.cpp)) # .cpp
? $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
$(SUBDIR)/client : $(addprefix $(SUBDIR)/,$(patsubst %.cpp,%.o,client.cpp)) # .cpp
? $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
$(SUBDIR)/%.o : %.cpp | $(SUBDIR) # .cpp
? $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
$(SUBDIR) : ; @ mkdir $@
-include $(SUBDIR)/*.d
clean : ; -rm -fr $(SUBDIR)
.PHONY : all clean
---
// ./boost_1_81_0/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp
#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>
#ifndef NDEBUG
#include <sanitizer/lsan_interface.h>
#endif
struct session
? : public std::enable_shared_from_this<session>
{
? session(boost::asio::ip::tcp::socket socket)
? ? : socket(std::move(socket))
? { }
? void start() {
? ? start_read();
? ? start_write();
? }
? void start_read() {
? ? auto self(shared_from_this());
? ? memset(input_data, 0, sizeof(input_data));
? ? socket.async_read_some(
? ? ? boost::asio::buffer(input_data, sizeof(input_data)),
? ? ? [&, self](boost::system::error_code ec, std::size_t length) {
? ? ? ? if (!ec) {
? ? ? ? ? std::cout << input_data;
? ? ? ? ? start_read();
? ? ? ? } else {
? ? ? ? ? std::cout << ec.message() << "\n";
? ? ? ? }
? ? ? }
? ? );
? }
? void start_write() {
? ? auto self(shared_from_this());
? ? memset(output_data, 0, sizeof(output_data));
? ? snprintf(output_data, sizeof(output_data) - 1,
? ? ? "hello client %zu\n", cnt++);
? ? boost::asio::async_write(
? ? ? socket,
? ? ? boost::asio::buffer(output_data, sizeof(input_data)),
? ? ? [&, self](boost::system::error_code ec, std::size_t length)
? ? ? {
? ? ? ? if (!ec) {
? ? ? ? ? // sleep(1); //test
? ? ? ? ? start_write();
? ? ? ? } else {
? ? ? ? ? std::cout << ec.message() << "\n";
? ? ? ? }
? ? ? }
? ? );
? }
? boost::asio::ip::tcp::socket socket;
? enum { LEN = 1024 };
? char input_data[LEN];
? char output_data[LEN];
? size_t cnt = 0;
};
struct server {
? server(boost::asio::io_context& io_context, short port)
? ? : acceptor(io_context, boost::asio::ip::tcp::endpoint(
? ? ? ? boost::asio::ip::tcp::v4(), port))
? {
? ? std::cout << "Listen on port: " << port << " \n";
? ? do_accept();
? }
? void do_accept() {
? ? acceptor.async_accept(
? ? ? [&](boost::system::error_code ec,
? ? ? ? boost::asio::ip::tcp::socket socket)
? ? ? {
? ? ? ? if (!ec) {
? ? ? ? ? std::cout << "Accept connection: "
? ? ? ? ? ? << socket.remote_endpoint() << "\n";
? ? ? ? ? std::make_shared<session>(std::move(socket))->start();
? ? ? ? } else {
? ? ? ? ? std::cout << ec.message() << "\n";
? ? ? ? }
? ? ? ? do_accept();
? ? ? }
? ? );
? }
? boost::asio::ip::tcp::acceptor acceptor;
};
void handlerCont(int signum) {
? printf("SIGCONT %d\n", signum);
#ifndef NDEBUG
? __lsan_do_recoverable_leak_check();
#endif
}
int main(int argc, char* argv[]) {
? if (argc != 2) {
? ? std::cerr << "Usage: server <port>\n";
? ? return 1;
? }
? signal(SIGCONT, handlerCont); // kill -CONT 123 # pid
? boost::asio::io_context io_context;
? server s(io_context, std::atoi(argv[1]));
? io_context.run();
? return 0;
}
---
// ./boost_1_81_0/doc/html/boost_asio/example/cpp11/timeouts/async_tcp_client.cpp
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/write.hpp>
#include <iostream>
#include <string>
#ifndef NDEBUG
#include <sanitizer/lsan_interface.h>
#endif
std::string client_tag; //test
struct session
? : public std::enable_shared_from_this<session>
{
? session(boost::asio::ip::tcp::socket socket)
? ? : socket(std::move(socket))
? { }
? void start() {
? ? start_read();
? ? start_write();
? }
? void start_read() {
? ? auto self(shared_from_this());
? ? memset(input_data, 0, sizeof(input_data));
? ? socket.async_read_some(
? ? ? boost::asio::buffer(input_data, sizeof(input_data)),
? ? ? [&, self](boost::system::error_code ec, std::size_t length) {
? ? ? ? if (!ec) {
? ? ? ? ? std::cout << input_data;
? ? ? ? ? start_read();
? ? ? ? } else {
? ? ? ? ? std::cout << ec.message() << "\n";
? ? ? ? }
? ? ? }
? ? );
? }
? void start_write() {
? ? auto self(shared_from_this());
? ? memset(output_data, 0, sizeof(output_data));
? ? snprintf(output_data, sizeof(output_data) - 1,
? ? ? "hello server %s %zu\n", client_tag.c_str(), cnt++);
? ? boost::asio::async_write(
? ? ? socket,
? ? ? boost::asio::buffer(output_data, sizeof(input_data)),
? ? ? [&, self](boost::system::error_code ec, std::size_t length)
? ? ? {
? ? ? ? if (!ec) {
? ? ? ? ? // sleep(1); //test
? ? ? ? ? start_write();
? ? ? ? } else {
? ? ? ? ? std::cout << ec.message() << "\n";
? ? ? ? }
? ? ? }
? ? );
? }
? boost::asio::ip::tcp::socket socket;
? enum { LEN = 1024 };
? char input_data[LEN];
? char output_data[LEN];
? size_t cnt = 0;
};
struct client {
? client(boost::asio::io_context& io_context,
? ? boost::asio::ip::tcp::resolver::results_type endpoints)
? ? ? : socket(io_context), endpoints(endpoints)
? {
? ? do_connect(endpoints.begin());
? }
? void do_connect (
? ? boost::asio::ip::tcp::resolver::results_type::iterator
? ? endpoint_iter)
? {
? ? if (endpoint_iter != endpoints.end()) {
? ? ? socket.async_connect(
? ? ? ? endpoint_iter->endpoint(),
? ? ? ? [&](const boost::system::error_code ec)
? ? ? ? {
? ? ? ? ? if (!socket.is_open()) {
? ? ? ? ? ? std::cout << "Connect timed out\n";
? ? ? ? ? ? do_connect(++endpoint_iter);
? ? ? ? ? } else if (ec) {
? ? ? ? ? ? std::cout << "Connect error: " << ec.message() << "\n";
? ? ? ? ? ? socket.close();
? ? ? ? ? } else {
? ? ? ? ? ? std::cout << "Connected to " <<
? ? ? ? ? ? ? socket.remote_endpoint() << "\n";
? ? ? ? ? ? std::make_shared<session>(std::move(socket))->start();
? ? ? ? ? }
? ? ? ? }
? ? ? );
? ? }
? }
? boost::asio::ip::tcp::resolver::results_type endpoints;
? boost::asio::ip::tcp::socket socket;
};
void handlerCont(int signum){
? printf("SIGCONT %d\n", signum);
#ifndef NDEBUG
? __lsan_do_recoverable_leak_check();
#endif
}
int main(int argc, char* argv[]) {
? if (argc != 4) {
? ? std::cerr << "Usage: client <host> <port> <tag>\n";
? ? return 1;
? }
? signal(SIGCONT, handlerCont); // kill -CONT 123 # pid
? client_tag = argv[3];
? boost::asio::io_context io_context;
? boost::asio::ip::tcp::resolver r(io_context);
? client c(io_context, r.resolve(argv[1], argv[2]));
? io_context.run();
? return 0;
}