Browse Source

update echo-servers

ithewei 5 years ago
parent
commit
413aff662a
3 changed files with 209 additions and 154 deletions
  1. 25 10
      echo-servers/benchmark.sh
  2. 8 0
      echo-servers/build.sh
  3. 176 144
      echo-servers/poco_echo.cpp

+ 25 - 10
echo-servers/benchmark.sh

@@ -1,5 +1,27 @@
 #!/bin/bash
 
+host=127.0.0.1
+port=2000
+# client: fork numbers
+client=2
+time=10
+
+while getopts 'h:p:c:t:' opt
+do
+    case $opt in
+        h) host=$OPTARG;;
+        p) port=$OPTARG;;
+        c) client=$OPTARG;;
+        t) time=$OPTARG;;
+        *) exit -1;;
+    esac
+done
+
+echo host=$host
+echo port=$port
+echo client=$client
+echo time=$time
+
 SCRIPT_DIR=$(cd `dirname $0`; pwd)
 cd ${SCRIPT_DIR}/..
 
@@ -12,12 +34,10 @@ killall_echo_servers() {
 
 export LD_LIBRARY_PATH=lib:$LD_LIBRARY_PATH
 
-ip=127.0.0.1
-sport=2000
-port=$sport
-
 killall_echo_servers
 
+sport=$port
+
 if [ -x bin/libevent_echo ]; then
     let port++
     bin/libevent_echo $port &
@@ -62,14 +82,9 @@ fi
 
 sleep 1
 
-client=2
-time=10
-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
+    bin/webbench -q -c $client -t $time $host:$p
     sleep 1
 done
 

+ 8 - 0
echo-servers/build.sh

@@ -14,6 +14,14 @@ case ${UNAME} in
 esac
 
 # install muduo => https://github.com/chenshuo/muduo.git
+if false; then
+git clone https://github.com/chenshuo/muduo.git
+pushd muduo
+mkdir build && cd build
+make && sudo make install
+popd
+fi
 
 make libhv && sudo make install
+make echo-servers
 make webbench

+ 176 - 144
echo-servers/poco_echo.cpp

@@ -1,4 +1,36 @@
-// @see poco/Net/samples/EchoServer
+//
+// 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"
@@ -8,186 +40,186 @@
 #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;
-	}
-	
+    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;
-	FIFOBuffer     _fifoIn;
-	FIFOBuffer     _fifoOut;
+    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()
-	{
-	}
-	
-	~EchoServer()
-	{
-	}
+    EchoServer(): _helpRequested(false)
+    {
+    }
+
+    ~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;
+    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();
         }
-        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);
+    EchoServer app;
+    return app.run(argc, argv);
 }