initial commit

This commit is contained in:
2025-08-05 15:53:44 +08:00
commit 09dc02ae52
553 changed files with 137665 additions and 0 deletions

105
third_party/libhv/echo-servers/asio_echo.cpp vendored Executable file
View File

@@ -0,0 +1,105 @@
//
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class session {
public:
session(boost::asio::io_service& io_service) :
socket_(io_service) {
}
tcp::socket& socket() {
return socket_;
}
void start() {
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred) {
if (!error) {
boost::asio::async_write(socket_, boost::asio::buffer(data_,
bytes_transferred), boost::bind(&session::handle_write,
this, boost::asio::placeholders::error));
} else {
delete this;
}
}
void handle_write(const boost::system::error_code& error) {
if (!error) {
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
} else {
delete this;
}
}
private:
tcp::socket socket_;
enum {
max_length = 1024
};
char data_[max_length];
};
class server {
public:
server(boost::asio::io_service& io_service, short port) :
io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(),
port)) {
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(), boost::bind(
&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error) {
if (!error) {
new_session->start();
new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(), boost::bind(
&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
} else {
delete new_session;
}
}
private:
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: cmd port\n");
return -10;
}
int port = atoi(argv[1]);
boost::asio::io_service io_service;
server s(io_service, port);
io_service.run();
return 0;
}

88
third_party/libhv/echo-servers/benchmark.sh vendored Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/bash
host=127.0.0.1
port=2000
connections=100
duration=10
threads=2
sendbytes=1024
while getopts 'h:p:c:d:t:' opt
do
case $opt in
h) host=$OPTARG;;
p) port=$OPTARG;;
c) connections=$OPTARG;;
d) duration=$OPTARG;;
t) threads=$OPTARG;;
*) exit -1;;
esac
done
SCRIPT_DIR=$(cd `dirname $0`; pwd)
cd ${SCRIPT_DIR}/..
killall_echo_servers() {
#sudo killall libevent_echo libev_echo libuv_echo libhv_echo asio_echo poco_echo muduo_echo
if [ $(ps aux | grep _echo | grep -v grep | wc -l) -gt 0 ]; then
ps aux | grep _echo | grep -v grep | awk '{print $2}' | xargs sudo kill -9
fi
}
export LD_LIBRARY_PATH=lib:$LD_LIBRARY_PATH
killall_echo_servers
sport=$port
if [ -x bin/libevent_echo ]; then
let port++
bin/libevent_echo $port &
echo "libevent running on port $port"
fi
if [ -x bin/libev_echo ]; then
let port++
bin/libev_echo $port &
echo "libev running on port $port"
fi
if [ -x bin/libuv_echo ]; then
let port++
bin/libuv_echo $port &
echo "libuv running on port $port"
fi
if [ -x bin/libhv_echo ]; then
let port++
bin/libhv_echo $port &
echo "libhv running on port $port"
fi
if [ -x bin/asio_echo ]; then
let port++
bin/asio_echo $port &
echo "asio running on port $port"
fi
if [ -x bin/poco_echo ]; then
let port++
bin/poco_echo $port &
echo "poco running on port $port"
fi
if [ -x bin/muduo_echo ]; then
let port++
bin/muduo_echo $port &
echo "muduo running on port $port"
fi
sleep 1
for ((p=$sport+1; p<=$port; ++p)); do
echo -e "\n==============$p====================================="
bin/pingpong_client -H $host -p $p -c $connections -d $duration -t $threads -b $sendbytes
sleep 1
done
killall_echo_servers

38
third_party/libhv/echo-servers/build.sh vendored Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/bash
SCRIPT_DIR=$(cd `dirname $0`; pwd)
ROOT_DIR=${SCRIPT_DIR}/..
# install libevent libev libuv asio poco
UNAME=$(uname -a)
case ${UNAME} in
*Ubuntu*|*Debian*)
sudo apt install libevent-dev libev-dev libuv1-dev libboost-dev libboost-system-dev libasio-dev libpoco-dev
;;
*CentOS*)
sudo yum install libevent-devel libev-devel libuv-devel boost-devel asio-devel poco-devel
;;
*Darwin*)
brew install libevent libev libuv boost asio poco
;;
*)
echo 'please install libevent libev libuv boost asio poco'
;;
esac
# install muduo => https://github.com/chenshuo/muduo.git
TEST_MUDUO=false
if [ "$TEST_MUDUO" == "true" ]; then
cd ${ROOT_DIR}/..
git clone https://github.com/chenshuo/muduo.git
cd muduo
mkdir build && cd build
cmake .. && make && sudo make install
fi
# install libhv
cd ${ROOT_DIR}
make libhv && sudo make install && sudo ldconfig
# build echo-servers
make echo-servers

78
third_party/libhv/echo-servers/libev_echo.c vendored Executable file
View File

@@ -0,0 +1,78 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "ev.h"
#define RECV_BUFSIZE 8192
static char recvbuf[RECV_BUFSIZE];
void do_recv(struct ev_loop *loop, struct ev_io *io, int revents) {
int nread, nsend;
nread = recv(io->fd, recvbuf, RECV_BUFSIZE, 0);
if (nread <= 0) {
goto error;
}
nsend = send(io->fd, recvbuf, nread, 0);
if (nsend != nread) {
goto error;
}
return;
error:
ev_io_stop(loop, io);
close(io->fd);
free(io);
}
void do_accept(struct ev_loop *loop, struct ev_io *listenio, int revents) {
struct sockaddr_in peeraddr;
socklen_t addrlen = sizeof(peeraddr);
int connfd = accept(listenio->fd, (struct sockaddr*)&peeraddr, &addrlen);
if (connfd <= 0) {
return;
}
struct ev_io* io = (struct ev_io*)malloc(sizeof(struct ev_io));
ev_io_init(io, do_recv, connfd, EV_READ);
ev_io_start(loop, io);
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: cmd port\n");
return -10;
}
int port = atoi(argv[1]);
struct sockaddr_in addr;
int addrlen = sizeof(addr);
memset(&addr, 0, addrlen);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd < 0) {
return -20;
}
if (bind(listenfd, (struct sockaddr*)&addr, addrlen) < 0) {
return -30;
}
if (listen(listenfd, SOMAXCONN) < 0) {
return -40;
}
struct ev_loop* loop = ev_loop_new(0);
struct ev_io listenio;
ev_io_init(&listenio, do_accept, listenfd, EV_READ);
ev_io_start(loop, &listenio);
ev_run(loop, 0);
ev_loop_destroy(loop);
return 0;
}

View File

@@ -0,0 +1,61 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event2/event.h"
#include "event2/listener.h"
#include "event2/bufferevent.h"
#include "event2/buffer.h"
//#define RECV_BUFSIZE 8192
void error_cb(struct bufferevent* bev, short event, void* userdata) {
bufferevent_free(bev);
}
void read_cb(struct bufferevent* bev, void* userdata) {
//static char recvbuf[RECV_BUFSIZE];
//int nread = bufferevent_read(bev, &recvbuf, RECV_BUFSIZE);
//bufferevent_write(bev, recvbuf, nread);
struct evbuffer* buf = evbuffer_new();
int ret = bufferevent_read_buffer(bev, buf);
if (ret == 0) {
bufferevent_write_buffer(bev, buf);
}
evbuffer_free(buf);
}
void on_accept(struct evconnlistener* listener, evutil_socket_t connfd, struct sockaddr* peeraddr, int addrlen, void* userdata) {
struct event_base* loop = evconnlistener_get_base(listener);
struct bufferevent* bev = bufferevent_socket_new(loop, connfd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, read_cb, NULL, error_cb, NULL);
bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: cmd port\n");
return -10;
}
int port = atoi(argv[1]);
struct event_base* loop = event_base_new();
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
struct evconnlistener* listener = evconnlistener_new_bind(
loop, on_accept, NULL,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
-1, (struct sockaddr*)&addr, sizeof(addr));
if (listener == NULL) {
return -20;
}
event_base_dispatch(loop);
evconnlistener_free(listener);
event_base_free(loop);
return 0;
}

31
third_party/libhv/echo-servers/libhv_echo.c vendored Executable file
View File

@@ -0,0 +1,31 @@
#include "hv/hloop.h"
void on_close(hio_t* io) {
}
void on_recv(hio_t* io, void* buf, int readbytes) {
hio_write(io, buf, readbytes);
}
void on_accept(hio_t* io) {
hio_setcb_close(io, on_close);
hio_setcb_read(io, on_recv);
hio_read(io);
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: cmd port\n");
return -10;
}
int port = atoi(argv[1]);
hloop_t* loop = hloop_new(0);
hio_t* listenio = hloop_create_tcp_server(loop, "0.0.0.0", port, on_accept);
if (listenio == NULL) {
return -20;
}
hloop_run(loop);
hloop_free(&loop);
return 0;
}

75
third_party/libhv/echo-servers/libuv_echo.c vendored Executable file
View File

@@ -0,0 +1,75 @@
#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uv.h"
typedef struct {
uv_write_t req;
uv_buf_t buf;
} uv_write_req_t;
void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
void close_cb(uv_handle_t* handle) {
free(handle);
}
void write_cb(uv_write_t* req, int status) {
uv_write_req_t* wr = (uv_write_req_t*)req;
free(wr->buf.base);
free(wr);
}
void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
if (nread <= 0) {
uv_close((uv_handle_t*)stream, close_cb);
return;
}
uv_write_req_t* wr = (uv_write_req_t*)malloc(sizeof(uv_write_req_t));
wr->buf.base = buf->base;
wr->buf.len = nread;
uv_write(&wr->req, stream, &wr->buf, 1, write_cb);
}
void do_accept(uv_stream_t* server, int status) {
uv_tcp_t* tcp_stream = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
uv_tcp_init(server->loop, tcp_stream);
uv_accept(server, (uv_stream_t*)tcp_stream);
uv_read_start((uv_stream_t*)tcp_stream, alloc_cb, read_cb);
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: cmd port\n");
return -10;
}
int port = atoi(argv[1]);
uv_loop_t loop;
uv_loop_init(&loop);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
//addr.sin_family = AF_INET;
//addr.sin_port = htons(port);
uv_ip4_addr("0.0.0.0", port, &addr);
uv_tcp_t tcp_server;
uv_tcp_init(&loop, &tcp_server);
int ret = uv_tcp_bind(&tcp_server, (struct sockaddr*)&addr, 0);
if (ret) {
return -20;
}
ret = uv_listen((uv_stream_t*)&tcp_server, SOMAXCONN, do_accept);
if (ret) {
return -30;
}
uv_run(&loop, UV_RUN_DEFAULT);
return 0;
}

62
third_party/libhv/echo-servers/muduo_echo.cpp vendored Executable file
View File

@@ -0,0 +1,62 @@
// @see muduo/examples/simple/echo
#include "muduo/base/Logging.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/InetAddress.h"
#include "muduo/net/TcpServer.h"
using std::placeholders::_1;
using std::placeholders::_2;
using std::placeholders::_3;
using muduo::Timestamp;
using muduo::net::EventLoop;
using muduo::net::InetAddress;
using muduo::net::TcpServer;
using muduo::net::TcpConnectionPtr;
using muduo::net::Buffer;
class EchoTcpServer {
public:
EchoTcpServer(EventLoop* loop, const InetAddress& addr)
: server_(loop, addr, "EchoTcpServer")
{
server_.setConnectionCallback(std::bind(&EchoTcpServer::onConnection, this, _1));
server_.setMessageCallback(std::bind(&EchoTcpServer::onMessage, this, _1, _2, _3));
}
void start() {
server_.start();
}
private:
void onConnection(const TcpConnectionPtr& conn) {
}
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf, Timestamp time) {
muduo::string msg(buf->retrieveAllAsString());
conn->send(msg);
}
TcpServer server_;
};
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: cmd port\n");
return -10;
}
int port = atoi(argv[1]);
muduo::g_logLevel = muduo::Logger::ERROR;
muduo::net::EventLoop loop;
muduo::net::InetAddress addr(port);
EchoTcpServer server(&loop, addr);
server.start();
loop.loop();
return 0;
}

View File

@@ -0,0 +1,143 @@
#include "hv/hmain.h" // import parse_opt
#include "hv/hloop.h"
#include "hv/hsocket.h"
#include "hv/EventLoopThreadPool.h"
using namespace hv;
static const char options[] = "hvH:p:c:d:t:b:";
static const char detail_options[] = R"(
-h Print help infomation
-v Show verbose infomation
-H <Host> default 127.0.0.1
-p <port>
-c <connections> Number of connections, default: 1000
-d <duration> Duration of test, default: 10s
-t <threads> Number of threads, default: 4
-b <bytes> Bytes of send buffer, default: 4096
)";
static int connections = 1000;
static int duration = 10;
static int threads = 4;
static bool verbose = false;
static const char* host = "127.0.0.1";
static int port = 0;
static int sendbytes = 4096;
static void* sendbuf = NULL;
static std::atomic<int> connected_num(0);
static std::atomic<int> disconnected_num(0);
static std::atomic<uint64_t> total_readcount(0);
static std::atomic<uint64_t> total_readbytes(0);
static void print_help() {
printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
printf("Options:\n%s\n", detail_options);
}
static void print_cmd() {
printf("Running %ds test @ %s:%d\n", duration, host, port);
printf("%d threads and %d connections, send %d bytes each time\n", threads, connections, sendbytes);
}
static void print_result() {
printf("total readcount=%llu readbytes=%llu\n",
(unsigned long long)total_readcount,
(unsigned long long)total_readbytes);
printf("throughput = %llu MB/s\n", (total_readbytes) / ((unsigned long long)duration * 1024 * 1024));
}
static void on_close(hio_t* io) {
if (++disconnected_num == connections) {
if (verbose) {
printf("all disconnected\n");
}
}
}
static void on_recv(hio_t* io, void* buf, int readbytes) {
++total_readcount;
total_readbytes += readbytes;
hio_write(io, buf, readbytes);
}
static void on_connect(hio_t* io) {
if (++connected_num == connections) {
if (verbose) {
printf("all connected\n");
}
}
hio_write(io, sendbuf, sendbytes);
hio_setcb_read(io, on_recv);
hio_read_start(io);
}
static void start_connect(hloop_t* loop) {
hio_t* io = hio_create_socket(loop, host, port, HIO_TYPE_TCP, HIO_CLIENT_SIDE);
if (io == NULL) {
perror("socket");
exit(1);
}
tcp_nodelay(hio_fd(io), 1);
hio_setcb_connect(io, on_connect);
hio_setcb_close(io, on_close);
hio_connect(io);
}
int main(int argc, char** argv) {
// parse cmdline
main_ctx_init(argc, argv);
int ret = parse_opt(argc, argv, options);
if (ret != 0) {
print_help();
exit(ret);
}
const char* strHost = get_arg("H");
const char* strPort = get_arg("p");
const char* strConnections = get_arg("c");
const char* strDuration = get_arg("d");
const char* strThreads = get_arg("t");
const char* strBytes = get_arg("b");
if (strHost) host = strHost;
if (strPort) port = atoi(strPort);
if (strConnections) connections = atoi(strConnections);
if (strDuration) duration = atoi(strDuration);
if (strThreads) threads = atoi(strThreads);
if (strBytes) sendbytes = atoi(strBytes);
if (get_arg("h") || port == 0) {
print_help();
exit(0);
}
if (get_arg("v")) {
verbose = true;
}
sendbuf = malloc(sendbytes);
print_cmd();
EventLoopThreadPool loop_threads(threads);
loop_threads.start(true);
for (int i = 0; i < connections; ++i) {
EventLoopPtr loop = loop_threads.nextLoop();
loop->runInLoop(std::bind(start_connect, loop->loop()));
}
// stop after seconds
loop_threads.loop()->setTimeout(duration * 1000, [&loop_threads](TimerID timerID){
loop_threads.stop(false);
});
// wait loop_threads exit
loop_threads.join();
print_result();
return 0;
}

225
third_party/libhv/echo-servers/poco_echo.cpp vendored Executable file
View File

@@ -0,0 +1,225 @@
//
// EchoServer.cpp
//
// $Id: //poco/1.3/Net/samples/EchoServer/src/EchoServer.cpp#1 $
//
// This sample demonstrates the SocketReactor and SocketAcceptor classes.
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/SocketAcceptor.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/NObserver.h"
#include "Poco/Exception.h"
#include "Poco/Thread.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include <iostream>
using Poco::Net::SocketReactor;
using Poco::Net::SocketAcceptor;
using Poco::Net::ReadableNotification;
using Poco::Net::ShutdownNotification;
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::NObserver;
using Poco::AutoPtr;
using Poco::Thread;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
class EchoServiceHandler
{
public:
EchoServiceHandler(StreamSocket& socket, SocketReactor& reactor):
_socket(socket),
_reactor(reactor),
_pBuffer(new char[BUFFER_SIZE])
{
// Application& app = Application::instance();
// app.logger().information("Connection from " + socket.peerAddress().toString());
_reactor.addEventHandler(_socket, NObserver<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onReadable));
_reactor.addEventHandler(_socket, NObserver<EchoServiceHandler, ShutdownNotification>(*this, &EchoServiceHandler::onShutdown));
}
~EchoServiceHandler()
{
// Application& app = Application::instance();
// app.logger().information("Disconnecting " + _socket.peerAddress().toString());
_reactor.removeEventHandler(_socket, NObserver<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onReadable));
_reactor.removeEventHandler(_socket, NObserver<EchoServiceHandler, ShutdownNotification>(*this, &EchoServiceHandler::onShutdown));
delete [] _pBuffer;
}
void onReadable(const AutoPtr<ReadableNotification>& pNf)
{
int n = _socket.receiveBytes(_pBuffer, BUFFER_SIZE);
if (n > 0)
_socket.sendBytes(_pBuffer, n);
else
delete this;
}
void onShutdown(const AutoPtr<ShutdownNotification>& pNf)
{
delete this;
}
private:
enum
{
BUFFER_SIZE = 1024
};
StreamSocket _socket;
SocketReactor& _reactor;
char* _pBuffer;
};
class EchoServer: public Poco::Util::ServerApplication
/// The main application class.
///
/// This class handles command-line arguments and
/// configuration files.
/// Start the EchoServer executable with the help
/// option (/help on Windows, --help on Unix) for
/// the available command line options.
///
/// To use the sample configuration file (EchoServer.properties),
/// copy the file to the directory where the EchoServer executable
/// resides. If you start the debug version of the EchoServer
/// (EchoServerd[.exe]), you must also create a copy of the configuration
/// file named EchoServerd.properties. In the configuration file, you
/// can specify the port on which the server is listening (default
/// 9977) and the format of the date/time string sent back to the client.
///
/// To test the EchoServer you can use any telnet client (telnet localhost 9977).
{
public:
EchoServer(): _helpRequested(false)
{
}
~EchoServer()
{
}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize()
{
ServerApplication::uninitialize();
}
void defineOptions(OptionSet& options)
{
ServerApplication::defineOptions(options);
options.addOption(
Option("help", "h", "display help information on command line arguments")
.required(false)
.repeatable(false));
}
void handleOption(const std::string& name, const std::string& value)
{
ServerApplication::handleOption(name, value);
if (name == "help")
_helpRequested = true;
}
void displayHelp()
{
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("An echo server implemented using the Reactor and Acceptor patterns.");
helpFormatter.format(std::cout);
}
int main(const std::vector<std::string>& args)
{
if (_helpRequested)
{
displayHelp();
}
else
{
if (args.size() < 1) {
printf("Usage: cmd port\n");
return -10;
}
int port = atoi(args[0].c_str());
// set-up a server socket
ServerSocket svs(port);
// set-up a SocketReactor...
SocketReactor reactor;
// ... and a SocketAcceptor
SocketAcceptor<EchoServiceHandler> acceptor(svs, reactor);
// run the reactor in its own thread so that we can wait for
// a termination request
Thread thread;
thread.start(reactor);
// wait for CTRL-C or kill
waitForTerminationRequest();
// Stop the SocketReactor
reactor.stop();
thread.join();
}
return Application::EXIT_OK;
}
private:
bool _helpRequested;
};
int main(int argc, char** argv)
{
EchoServer app;
return app.run(argc, argv);
}