Parcourir la source

echo-servers/benchmark

hewei il y a 6 ans
Parent
commit
f83d8fde98

+ 17 - 60
Makefile

@@ -1,3 +1,5 @@
+include Makefile.vars
+
 MAKEF=$(MAKE) -f Makefile.in
 TMPDIR=tmp
 
@@ -15,6 +17,8 @@ prepare:
 libhv: prepare
 	$(MAKEF) TARGET=$@ TARGET_TYPE=SHARED SRCDIRS=". base utils event http http/client http/server protocol"
 	$(MAKEF) TARGET=$@ TARGET_TYPE=STATIC SRCDIRS=". base utils event http http/client http/server protocol"
+	-mkdir include
+	-cp $(INSTALL_HEADERS) include/
 
 test: prepare
 	-rm $(TMPDIR)/*.o $(TMPDIR)/*.h $(TMPDIR)/*.c $(TMPDIR)/*.cpp
@@ -86,69 +90,22 @@ unittest: prepare
 	$(CC)  -g -Wall -std=c99   -I. -Ibase -Iprotocol -o bin/ftp        unittest/ftp_test.c           protocol/ftp.c  base/hsocket.c
 	$(CC)  -g -Wall -std=c99   -I. -Ibase -Iutils -Iprotocol -o bin/sendmail  unittest/sendmail_test.c  protocol/smtp.c base/hsocket.c utils/base64.c
 
-INSTALL_HEADERS=hv.h\
-				\
-				hconfig.h\
-				base/hplatform.h\
-				\
-				base/hdef.h\
-				base/hversion.h\
-				base/hbase.h\
-				base/hsysinfo.h\
-				base/hproc.h\
-				base/hmath.h\
-				base/htime.h\
-				base/herr.h\
-				base/hlog.h\
-				base/hmutex.h\
-				base/hthread.h\
-				base/hsocket.h\
-				base/hbuf.h\
-				base/hurl.h\
-				base/hgui.h\
-				base/ssl_ctx.h\
-				\
-				base/hstring.h\
-				base/hvar.h\
-				base/hobj.h\
-				base/hfile.h\
-				base/hdir.h\
-				base/hscope.h\
-				base/hthreadpool.h\
-				base/hobjectpool.h\
-				\
-				utils/base64.h\
-				utils/md5.h\
-				utils/json.hpp\
-				utils/singleton.h\
-				utils/ifconfig.h\
-				utils/iniparser.h\
-				utils/hendian.h\
-				utils/hmain.h\
-				\
-				event/hloop.h\
-				event/nlog.h\
-				event/nmap.h\
-				\
-				http/httpdef.h\
-				http/http2def.h\
-				http/grpcdef.h\
-				http/http_content.h\
-				http/HttpMessage.h\
-				http/client/http_client.h\
-				http/server/HttpService.h\
-				http/server/HttpServer.h\
-				\
-				protocol/icmp.h\
-				protocol/dns.h\
-				protocol/ftp.h\
-				protocol/smtp.h
 install:
-	-mkdir include
-	-cp $(INSTALL_HEADERS) include/
+	-mkdir -p $(INSTALL_INCDIR)
+	-cp include/* $(INSTALL_INCDIR)
+	-cp lib/libhv.a lib/libhv.so $(INSTALL_LIBDIR)
 
 # UNIX only
 webbench: prepare
 	$(CC) -o bin/webbench unittest/webbench.c
 
-.PHONY: clean prepare libhv test timer loop tcp udp nc nmap httpd curl consul_cli unittest webbench install
+echo-servers:
+	$(CC)  -g -Wall -std=c99   -o bin/libevent_echo echo-servers/libevent_echo.c -levent
+	$(CC)  -g -Wall -std=c99   -o bin/libev_echo    echo-servers/libev_echo.c    -lev
+	$(CC)  -g -Wall -std=c99   -o bin/libuv_echo    echo-servers/libuv_echo.c    -luv
+	$(CC)  -g -Wall -std=c99   -o bin/libhv_echo    echo-servers/libhv_echo.c    -Iinclude -Llib -lhv
+	$(CXX) -g -Wall -std=c++11 -o bin/asio_echo     echo-servers/asio_echo.cpp   -lboost_system
+	$(CXX) -g -Wall -std=c++11 -o bin/poco_echo     echo-servers/poco_echo.cpp   -lPocoNet -lPocoUtil -lPocoFoundation
+	$(CXX) -g -Wall -std=c++11 -o bin/muduo_echo    echo-servers/muduo_echo.cpp  -lmuduo_net -lmuduo_base -lpthread
+
+.PHONY: clean prepare libhv test timer loop tcp udp nc nmap httpd curl consul_cli unittest install webbench echo-servers

+ 60 - 0
Makefile.vars

@@ -0,0 +1,60 @@
+INSTALL_INCDIR=/usr/local/include/hv
+INSTALL_LIBDIR=/usr/local/lib
+
+INSTALL_HEADERS=hv.h\
+				\
+				hconfig.h\
+				base/hplatform.h\
+				\
+				base/hdef.h\
+				base/hversion.h\
+				base/hbase.h\
+				base/hsysinfo.h\
+				base/hproc.h\
+				base/hmath.h\
+				base/htime.h\
+				base/herr.h\
+				base/hlog.h\
+				base/hmutex.h\
+				base/hthread.h\
+				base/hsocket.h\
+				base/hbuf.h\
+				base/hurl.h\
+				base/hgui.h\
+				base/ssl_ctx.h\
+				\
+				base/hstring.h\
+				base/hvar.h\
+				base/hobj.h\
+				base/hfile.h\
+				base/hdir.h\
+				base/hscope.h\
+				base/hthreadpool.h\
+				base/hobjectpool.h\
+				\
+				utils/base64.h\
+				utils/md5.h\
+				utils/json.hpp\
+				utils/singleton.h\
+				utils/ifconfig.h\
+				utils/iniparser.h\
+				utils/hendian.h\
+				utils/hmain.h\
+				\
+				event/hloop.h\
+				event/nlog.h\
+				event/nmap.h\
+				\
+				http/httpdef.h\
+				http/http2def.h\
+				http/grpcdef.h\
+				http/http_content.h\
+				http/HttpMessage.h\
+				http/client/http_client.h\
+				http/server/HttpService.h\
+				http/server/HttpServer.h\
+				\
+				protocol/icmp.h\
+				protocol/dns.h\
+				protocol/ftp.h\
+				protocol/smtp.h

+ 22 - 32
README.md

@@ -29,9 +29,9 @@ but simpler apis and richer protocols.
 
 ## Getting Started
 
-### http
+### http server
 see examples/httpd.cpp
-```
+```c++
 #include "HttpServer.h"
 
 int http_api_hello(HttpRequest* req, HttpResponse* res) {
@@ -78,43 +78,22 @@ bin/webbench -c 2 -t 60 localhost:8080
 **libhv(port:8080) vs nginx(port:80)**
 ![libhv-vs-nginx.png](html/downloads/libhv-vs-nginx.png)
 
-### event-loop
-see examples/tcp.c
-```
+### EventLoop
+see examples/tcp.c examples/udp.c
+```c
+// TCP echo server
 #include "hloop.h"
-#include "hsocket.h"
-
-#define RECV_BUFSIZE    8192
-static char recvbuf[RECV_BUFSIZE];
 
 void on_close(hio_t* io) {
-    printf("on_close fd=%d error=%d\n", hio_fd(io), hio_error(io));
 }
 
 void on_recv(hio_t* io, void* buf, int readbytes) {
-    printf("on_recv fd=%d readbytes=%d\n", hio_fd(io), readbytes);
-    char localaddrstr[SOCKADDR_STRLEN] = {0};
-    char peeraddrstr[SOCKADDR_STRLEN] = {0};
-    printf("[%s] <=> [%s]\n",
-            SOCKADDR_STR(hio_localaddr(io), localaddrstr),
-            SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
-    printf("< %s\n", buf);
-    // echo
-    printf("> %s\n", buf);
     hio_write(io, buf, readbytes);
 }
 
 void on_accept(hio_t* io) {
-    printf("on_accept connfd=%d\n", hio_fd(io));
-    char localaddrstr[SOCKADDR_STRLEN] = {0};
-    char peeraddrstr[SOCKADDR_STRLEN] = {0};
-    printf("accept connfd=%d [%s] <= [%s]\n", hio_fd(io),
-            SOCKADDR_STR(hio_localaddr(io), localaddrstr),
-            SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
-
     hio_setcb_close(io, on_close);
     hio_setcb_read(io, on_recv);
-    hio_set_readbuf(io, recvbuf, RECV_BUFSIZE);
     hio_read(io);
 }
 
@@ -130,26 +109,25 @@ int main(int argc, char** argv) {
     if (listenio == NULL) {
         return -20;
     }
-    printf("listenfd=%d\n", hio_fd(listenio));
     hloop_run(loop);
     hloop_free(&loop);
     return 0;
 }
 ```
-```
+```shell
 make tcp udp nc
 bin/tcp 1111
-bin/nc 1111
+bin/nc 127.0.0.1 1111
 
 bin/udp 2222
-bin/nc -u 2222
+bin/nc -u 127.0.0.1 2222
 ```
 
 ## BUILD
 
 ### lib
 - make libhv
-- make install
+- sudo make install
 
 ### examples
 - make test # master-workers model
@@ -183,6 +161,18 @@ bin/nc -u 2222
 - WITH_WINDUMP
 - USE_MULTIMAP
 
+### echo-servers/benchmark
+```shell
+make libhv
+make webbench
+
+# ubuntu16.04
+sudo apt-get install libevent-dev libev-dev libuv1-dev libboost-dev libasio-dev libpoco-dev
+# muduo install => https://github.com/chenshuo/muduo.git
+make echo-servers
+sudo echo-servers/benchmark.sh
+```
+
 ## Module
 
 ### data-structure

+ 105 - 0
echo-servers/asio_echo.cpp

@@ -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;
+}

+ 71 - 0
echo-servers/benchmark.sh

@@ -0,0 +1,71 @@
+#! /bin/bash
+
+killall_echo_servers() {
+    #sudo killall libevent_echo libev_echo libuv_echo libhv_echo asio_echo poco_echo muduo_echo
+    ps aux | grep _echo | grep -v grep | awk '{print $2}' | xargs sudo kill -9
+}
+
+export LD_LIBRARY_PATH=lib:$LD_LIBRARY_PATH
+
+ip=127.0.0.1
+sport=2000
+port=$sport
+
+killall_echo_servers
+
+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
+
+client=2
+time=60
+if [ $# -gt 0 ]; then
+    time=$1
+fi
+for ((p=$sport+1; p<=$port; ++p)); do
+    echo -e "\n==============$p====================================="
+    bin/webbench -q -c $client -t $time $ip:$p
+    sleep 1
+done
+
+killall_echo_servers

+ 78 - 0
echo-servers/libev_echo.c

@@ -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;
+}

+ 61 - 0
echo-servers/libevent_echo.c

@@ -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 - 0
echo-servers/libhv_echo.c

@@ -0,0 +1,31 @@
+#include "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 = 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 - 0
echo-servers/libuv_echo.c

@@ -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 = buf->len;
+    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 - 0
echo-servers/muduo_echo.cpp

@@ -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;
+}

+ 193 - 0
echo-servers/poco_echo.cpp

@@ -0,0 +1,193 @@
+// @see poco/Net/samples/EchoServer
+
+#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/FIFOBuffer.h"
+#include "Poco/Delegate.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::WritableNotification;
+using Poco::Net::ShutdownNotification;
+using Poco::Net::ServerSocket;
+using Poco::Net::StreamSocket;
+using Poco::NObserver;
+using Poco::AutoPtr;
+using Poco::Thread;
+using Poco::FIFOBuffer;
+using Poco::delegate;
+using Poco::Util::ServerApplication;
+using Poco::Util::Application;
+using Poco::Util::Option;
+using Poco::Util::OptionSet;
+using Poco::Util::HelpFormatter;
+
+class EchoServiceHandler
+	/// I/O handler class. This class (un)registers handlers for I/O based on
+	/// data availability. To ensure non-blocking behavior and alleviate spurious
+	/// socket writability callback triggering when no data to be sent is available,
+	/// FIFO buffers are used. I/O FIFOBuffer sends notifications on transitions
+	/// from [1] non-readable (i.e. empty) to readable, [2] writable to non-writable 
+	/// (i.e. full) and [3] non-writable (i.e. full) to writable.
+	/// Based on these notifications, the handler member functions react by
+	/// enabling/disabling respective reactor framework notifications.
+{
+public:
+	EchoServiceHandler(StreamSocket& socket, SocketReactor& reactor):
+		_socket(socket),
+		_reactor(reactor),
+		_fifoIn(BUFFER_SIZE, true),
+		_fifoOut(BUFFER_SIZE, true)
+	{
+		_reactor.addEventHandler(_socket, NObserver<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onSocketReadable));
+		_reactor.addEventHandler(_socket, NObserver<EchoServiceHandler, ShutdownNotification>(*this, &EchoServiceHandler::onSocketShutdown));
+
+		_fifoOut.readable += delegate(this, &EchoServiceHandler::onFIFOOutReadable);
+		_fifoIn.writable += delegate(this, &EchoServiceHandler::onFIFOInWritable);
+	}
+	
+	~EchoServiceHandler()
+	{
+		_reactor.removeEventHandler(_socket, NObserver<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onSocketReadable));
+		_reactor.removeEventHandler(_socket, NObserver<EchoServiceHandler, WritableNotification>(*this, &EchoServiceHandler::onSocketWritable));
+		_reactor.removeEventHandler(_socket, NObserver<EchoServiceHandler, ShutdownNotification>(*this, &EchoServiceHandler::onSocketShutdown));
+
+		_fifoOut.readable -= delegate(this, &EchoServiceHandler::onFIFOOutReadable);
+		_fifoIn.writable -= delegate(this, &EchoServiceHandler::onFIFOInWritable);
+	}
+	
+	void onFIFOOutReadable(bool& b)
+	{
+		if (b)
+			_reactor.addEventHandler(_socket, NObserver<EchoServiceHandler, WritableNotification>(*this, &EchoServiceHandler::onSocketWritable));
+		else
+			_reactor.removeEventHandler(_socket, NObserver<EchoServiceHandler, WritableNotification>(*this, &EchoServiceHandler::onSocketWritable));
+	}
+	
+	void onFIFOInWritable(bool& b)
+	{
+		if (b)
+			_reactor.addEventHandler(_socket, NObserver<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onSocketReadable));
+		else
+			_reactor.removeEventHandler(_socket, NObserver<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onSocketReadable));
+	}
+	
+	void onSocketReadable(const AutoPtr<ReadableNotification>& pNf)
+	{
+		try
+		{
+			int len = _socket.receiveBytes(_fifoIn);
+			if (len > 0)
+			{
+				_fifoIn.drain(_fifoOut.write(_fifoIn.buffer(), _fifoIn.used()));
+			}
+			else
+			{
+				delete this;
+			}
+		}
+		catch (Poco::Exception& exc)
+		{
+			Application& app = Application::instance();
+			app.logger().log(exc);
+			delete this;
+		}
+	}
+	
+	void onSocketWritable(const AutoPtr<WritableNotification>& pNf)
+	{
+		try
+		{
+			_socket.sendBytes(_fifoOut);
+		}
+		catch (Poco::Exception& exc)
+		{
+			Application& app = Application::instance();
+			app.logger().log(exc);
+			delete this;
+		}
+	}
+
+	void onSocketShutdown(const AutoPtr<ShutdownNotification>& pNf)
+	{
+		delete this;
+	}
+	
+private:
+	enum
+	{
+		BUFFER_SIZE = 1024
+	};
+	
+	StreamSocket   _socket;
+	SocketReactor& _reactor;
+	FIFOBuffer     _fifoIn;
+	FIFOBuffer     _fifoOut;
+};
+
+
+class EchoServer: public Poco::Util::ServerApplication
+{
+public:
+	EchoServer()
+	{
+	}
+	
+	~EchoServer()
+	{
+	}
+
+protected:
+	void initialize(Application& self)
+	{
+		ServerApplication::initialize(self);
+	}
+		
+	void uninitialize()
+	{
+		ServerApplication::uninitialize();
+	}
+
+	int main(const std::vector<std::string>& args)
+	{
+        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;
+	}
+};
+
+int main(int argc, char** argv)
+{
+	EchoServer app;
+	return app.run(argc, argv);
+}

+ 1 - 1
event/iowatcher.h

@@ -5,8 +5,8 @@
 
 #include "hplatform.h"
 #if !defined(EVENT_SELECT) &&   \
-    !defined(EVENT_EPOLL) &&    \
     !defined(EVENT_POLL) &&     \
+    !defined(EVENT_EPOLL) &&    \
     !defined(EVENT_KQUEUE) &&   \
     !defined(EVENT_IOCP) &&     \
     !defined(EVENT_PORT) &&     \