kezunlin · 2019年11月30日

Windows 10上源码编译Poco并编写httpserver和tcpserver

本文首发于个人博客https://kezunlin.me/post/9587bb47/,欢迎阅读!

compile and install poco cpp library on windows

Series

Guide

download

wget https://pocoproject.org/releases/poco-1.8.1/poco-1.8.1.zip
wget https://pocoproject.org/releases/poco-1.8.1/poco-1.8.1.tar.gz

build

build options

buildwin.cmd

    rem Usage:
    rem ------
    rem buildwin VS_VERSION [ACTION] [LINKMODE] [CONFIGURATION] [PLATFORM] [SAMPLES] [TESTS] [TOOL]
    rem VS_VERSION:    90|100|110|120|140|150
    rem ACTION:        build|rebuild|clean
    rem LINKMODE:      static_mt|static_md|shared|all
    rem CONFIGURATION: release|debug|both
    rem PLATFORM:      Win32|x64|WinCE|WEC2013
    rem SAMPLES:       samples|nosamples
    rem TESTS:         tests|notests
    rem TOOL:          devenv|vcexpress|wdexpress|msbuild

we choose to build with visual studio 2015

build_vs140.cmd

    @echo off
    buildwin 140 build shared release x64 samples

build

./build_vs140.cmd

or

cmake-gui ..

cmake-gui and open sln to build with release x64and install to C:/Program Files/Poco so that find_package(Poco REQURIED) take effect.

$ ls Poco

bin  include  lib

$ ll Poco/lib

total 3.5M
drwxr-xr-x 1 zunli zunli     0 Jan 25 07:39 cmake
-rw-r--r-- 1 zunli zunli  1.5M Jan 25 06:59 PocoFoundation.lib
-rw-r--r-- 1 zunli zunli  111K Jan 25 06:59 PocoJSON.lib
-rw-r--r-- 1 zunli zunli 1007K Jan 25 07:00 PocoNet.lib
-rw-r--r-- 1 zunli zunli  320K Jan 25 07:00 PocoUtil.lib
-rw-r--r-- 1 zunli zunli  595K Jan 25 07:00 PocoXML.lib

Poco Example

CMakeLists.txt

cmake_minimum_required (VERSION 2.6)

project (event_demo)
enable_language(C)
enable_language(CXX)

# Always include the source and build directories in the include path.
set(CMAKE_INCLUDE_CURRENT_DIR ON)

# Set the output folder where your program will be created
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})

find_package(Poco REQUIRED COMPONENTS Foundation Util Net XML JSON)

# no Poco_INCLUDE_DIRS, we have to set by hand 
if(MSVC) # WIN32
    SET(Poco_INCLUDE_DIRS "C:/Program Files/Poco/include")
else()
    SET(Poco_INCLUDE_DIRS "/usr/local/include/Poco")
endif(MSVC)

MESSAGE( [Main] " Poco_INCLUDE_DIRS = ${Poco_INCLUDE_DIRS}")
MESSAGE( [Main] " Poco_LIBRARIES = ${Poco_LIBRARIES}")

# The following folder will be included
include_directories(
    ${MY_SRC_INCLUDE}  
    ${Poco_INCLUDE_DIRS} 
    )   

link_directories(${CMAKE_BINARY_DIR}) 

add_executable(event_demo event_demo.cpp)
target_link_libraries(event_demo ${Poco_LIBRARIES})
Notice 1: find_package(Poco REQUIRED COMPONENTS Foundation Util Net XML JSON) and use ${Poco_INCLUDE_DIRS}, ${Poco_LIBRARIES}.

Notice 2: we have to set SET(Poco_INCLUDE_DIRS "C:/Program Files/Poco/include") by hand.

event

event_demo.cpp

#include "Poco/BasicEvent.h"
#include "Poco/Delegate.h"
#include <iostream>

using Poco::BasicEvent;
using Poco::Delegate;

class Source
{
public:
    BasicEvent<int> theEvent;

    void fireEvent(int n)
    {
        theEvent(this, n);
    }
};

class Target
{
public:
    void onEvent(const void* pSender, int& arg)
    {
        std::cout << "onEvent: " << arg << std::endl;
    }
};

int main(int argc, char** argv)
{
    Source source;
    Target target;

    source.theEvent += Delegate<Target, int>(
        &target, &Target::onEvent);

    source.fireEvent(42);

    source.theEvent -= Delegate<Target, int>(
        &target, &Target::onEvent);

    return 0;
}

active method

#include "Poco/ActiveMethod.h"
#include "Poco/ActiveResult.h"
#include <utility>
#include <iostream>

using Poco::ActiveMethod;
using Poco::ActiveResult;

class ActiveAdder
{
public:
    ActiveAdder() : add(this, &ActiveAdder::addImpl)
    {
    }

    ActiveMethod<int, std::pair<int, int>, ActiveAdder> add;

private:
    int addImpl(const std::pair<int, int>& args)
    {
        return args.first + args.second;
    }
};

int main(int argc, char** argv)
{
    ActiveAdder adder;

    ActiveResult<int> sum = adder.add(std::make_pair(1, 2));
    // do other things
    sum.wait();
    std::cout << sum.data() << std::endl;

    return 0;
}

http server

#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/Exception.h"
#include "Poco/ThreadPool.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::ServerSocket;
using Poco::Net::HTTPRequestHandler;
using Poco::Net::HTTPRequestHandlerFactory;
using Poco::Net::HTTPServer;
using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPServerResponse;
using Poco::Net::HTTPServerParams;
using Poco::Timestamp;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::ThreadPool;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::OptionCallback;
using Poco::Util::HelpFormatter;

class TimeRequestHandler : public HTTPRequestHandler
{
public:
    TimeRequestHandler(const std::string& format) : _format(format)
    {
    }

    void handleRequest(HTTPServerRequest& request,
        HTTPServerResponse& response)
    {
        Application& app = Application::instance();
        app.logger().information("[LOG] Request from "
            + request.clientAddress().toString());

        Timestamp now;
        std::string dt(DateTimeFormatter::format(now, _format));

        response.setChunkedTransferEncoding(true);
        response.setContentType("text/html");

        std::ostream& ostr = response.send();
        ostr << "<html><head><title>HTTPTimeServer powered by "
            "POCO C++ Libraries</title>";
        ostr << "<meta http-equiv=\"refresh\" content=\"1\"></head>";
        ostr << "<body><p style=\"text-align: center; "
            "font-size: 48px;\">";
        ostr << dt;
        ostr << "</p></body></html>";
    }

private:
    std::string _format;
};

class TimeRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    TimeRequestHandlerFactory(const std::string& format) :
        _format(format)
    {
    }

    HTTPRequestHandler* createRequestHandler(
        const HTTPServerRequest& request)
    {
        if (request.getURI() == "/")
            return new TimeRequestHandler(_format);
        else
            return 0;
    }

private:
    std::string _format;
};

class HTTPTimeServer : public Poco::Util::ServerApplication
{
public:
    HTTPTimeServer() : _helpRequested(false)
    {
    }

    ~HTTPTimeServer()
    {
    }

protected:
    void initialize(Application& self)
    {
        Application& app = Application::instance();
        app.logger().information("[HTTPTimeServer] initialize port=9980 ");

        loadConfiguration();
        ServerApplication::initialize(self);
    }

    void uninitialize()
    {
        Application& app = Application::instance();
        app.logger().information("[HTTPTimeServer] uninitialize ");

        ServerApplication::uninitialize();
    }

    void defineOptions(OptionSet& options)
    {
        ServerApplication::defineOptions(options);

        options.addOption(
            Option("help", "h", "display argument help information")
            .required(false)
            .repeatable(false)
            .callback(OptionCallback<HTTPTimeServer>(
                this, &HTTPTimeServer::handleHelp)));
    }

    void handleHelp(const std::string& name,
        const std::string& value)
    {
        HelpFormatter helpFormatter(options());
        helpFormatter.setCommand(commandName());
        helpFormatter.setUsage("OPTIONS");
        helpFormatter.setHeader(
            "A web server that serves the current date and time.");
        helpFormatter.format(std::cout);
        stopOptionsProcessing();
        _helpRequested = true;
    }

    int main(const std::vector<std::string>& args)
    {
        Application& app = Application::instance();
        app.logger().information("[HTTPTimeServer] main ");

        if (!_helpRequested)
        {
            unsigned short port = (unsigned short)
                config().getInt("HTTPTimeServer.port", 9980);
            std::string format(
                config().getString("HTTPTimeServer.format",
                    DateTimeFormat::SORTABLE_FORMAT));

            ServerSocket svs(port);
            HTTPServer srv(new TimeRequestHandlerFactory(format),
                svs, new HTTPServerParams);
            srv.start();
            waitForTerminationRequest();
            srv.stop();
        }
        return Application::EXIT_OK;
    }

private:
    bool _helpRequested;
};

int main(int argc, char** argv)
{
    HTTPTimeServer app;
    return app.run(argc, argv);
    //visit http://localhost:9980
}

tcp server/client

tcpserver

//
// TimeServer.cpp
//
// This sample demonstrates the TCPServer and ServerSocket classes.
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:    BSL-1.0
//


#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerParams.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/Exception.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::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::TCPServer;
using Poco::Timestamp;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;


class TimeServerConnection : public TCPServerConnection
    /// This class handles all client connections.
    ///
    /// A string with the current date and time is sent back to the client.
{
public:
    TimeServerConnection(const StreamSocket& s, const std::string& format) :
        TCPServerConnection(s),
        _format(format)
    {
    }

    void run()
    {
        Application& app = Application::instance();
        app.logger().information("Request from " + this->socket().peerAddress().toString());
        try
        {
            Timestamp now;
            //std::string dt(DateTimeFormatter::format(now, _format));
            //dt.append("\r\n");
            std::string dt("hello world");
            std::string info("sending:  [" + dt + "] with length="+std::to_string(dt.length()) );
            app.logger().information(info);
            socket().sendBytes(dt.data(), (int)dt.length());
        }
        catch (Poco::Exception& exc)
        {
            app.logger().log(exc);
        }
    }

private:
    std::string _format;
};


class TimeServerConnectionFactory : public TCPServerConnectionFactory
    /// A factory for TimeServerConnection.
{
public:
    TimeServerConnectionFactory(const std::string& format) :
        _format(format)
    {
    }

    TCPServerConnection* createConnection(const StreamSocket& socket)
    {
        return new TimeServerConnection(socket, _format);
    }

private:
    std::string _format;
};


class TimeServer : public Poco::Util::ServerApplication
    /// The main application class.
    ///
    /// This class handles command-line arguments and
    /// configuration files.
    /// Start the TimeServer executable with the help
    /// option (/help on Windows, --help on Unix) for
    /// the available command line options.
    ///
    /// To use the sample configuration file (TimeServer.properties),
    /// copy the file to the directory where the TimeServer executable
    /// resides. If you start the debug version of the TimeServer
    /// (TimeServerd[.exe]), you must also create a copy of the configuration
    /// file named TimeServerd.properties. In the configuration file, you
    /// can specify the port on which the server is listening (default
    /// 9911) and the format of the date/time string sent back to the client.
    ///
    /// To test the TimeServer you can use any telnet client (telnet localhost 9911).
{
public:
    TimeServer() : _helpRequested(false)
    {
    }

    ~TimeServer()
    {
    }

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("A server application that serves the current date and time.");
        helpFormatter.format(std::cout);
    }

    int main(const std::vector<std::string>& args)
    {
        if (_helpRequested)
        {
            displayHelp();
        }
        else
        {
            // get parameters from configuration file
            unsigned short port = (unsigned short)config().getInt("TimeServer.port", 9911);
            std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));

            // set-up a server socket
            ServerSocket svs(port);
            // set-up a TCPServer instance
            TCPServer srv(new TimeServerConnectionFactory(format), svs);
            // start the TCPServer
            srv.start();
            // wait for CTRL-C or kill
            waitForTerminationRequest();
            // Stop the TCPServer
            srv.stop();
        }
        return Application::EXIT_OK;
    }

private:
    bool _helpRequested;
};


int main(int argc, char** argv)
{
    TimeServer app; // 9911
    return app.run(argc, argv);
}

start tcpserver.

tcpclient

//
// TimeClient.cpp
//

#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/StreamSocket.h"
#include <iostream>

using Poco::Net::SocketAddress;
using Poco::Net::StreamSocket;

int main(int argc, char** argv)
{
    SocketAddress sa("127.0.0.1",9911);
    StreamSocket ss(sa);
    int n;
    char buffer[256];
    
    //n = 11 , s[0,1,2,....10] = hello world s[11]='\0'
    n = ss.receiveBytes(buffer, sizeof(buffer)-1);
    buffer[n] = '\0';

    std::cout << buffer << std::endl;
    std::cout << n << std::endl;
}

start tcpclient to receive data from tcpserver.

telnet as tcpclient

install telnet on windows by contron panel.

telnet localhost 9911

Reference

History

  • 20180125: created.

Copyright

推荐阅读
关注数
2
文章数
52
[链接] C++,Python. Computer Vision and Deep Learning.
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息