chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.85k stars 1.2k forks source link

Hello Asio #1232

Open lijh8 opened 1 year ago

lijh8 commented 1 year ago

Hello,

I think the existing examples and tutorials lack a simple and intuitive hello world style example. What do you guys think about this example.

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                   
4378 ljh       20   0   20.0t   6.4m   4.5m R  54.6   0.2   0:54.32 ./build/server 9995                                       
4418 ljh       20   0   20.0t   6.3m   4.4m R  17.6   0.2   0:18.60 ./build/client 192.168.1.4 9995 bbb                       
4384 ljh       20   0   20.0t   6.3m   4.4m S  22.5   0.2   0:30.48 ./build/client 192.168.1.4 9995 aaa    

// src/client.cpp

// ./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>
#include <sanitizer/lsan_interface.h>

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)),
      [this, 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)),
      [this, 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); // $ man 7 signal
  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;
}

// src/server.cpp

// ./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>
#include <sanitizer/lsan_interface.h>

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)),
      [this, 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)),
      [this, 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(
      [this](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); // $ man 7 signal

  boost::asio::io_context io_context;
  server s(io_context, std::atoi(argv[1]));
  io_context.run();

  return 0;
}