Poco :: Net :: TCPServer - 使用100%cpu的简单服务器

时间:2017-03-11 20:43:47

标签: multithreading cpu-usage poco tcpserver

我尝试用poco制作一个简单的tcp服务器。我使用Poco :: Net :: TCPServer类,这是一个多线程服务器,从技术上讲它是有效的。但有一件事是超级奇怪的。如果我启动服务器,获得一个或多个传入连接,我在3秒后获得100%的CPU使用率,但我无法弄清楚原因。

这是我的简单代码。

#include <iostream>
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerParams.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/Socket.h"

#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"

#include <string>
using namespace std;

class newConnection: public Poco::Net::TCPServerConnection {
public:
    newConnection(const Poco::Net::StreamSocket& s) :
        Poco::Net::TCPServerConnection(s) {
    }

    void run() {
        cout << "New connection from: " << socket().peerAddress().host().toString() <<  endl << flush;
        const auto ct = Poco::Thread::current();
        cout << "thread-id: " << ct->id() << endl;
        bool isOpen = true;
        Poco::Timespan timeOut(10,0);
        unsigned char incommingBuffer[1000];
        while(isOpen)
        {
            if (socket().poll(timeOut,Poco::Net::Socket::SELECT_READ) == false)
            {
                //cout << "TIMEOUT!" << endl << flush;
            }
            else
            {
                //cout << "RX EVENT!!! ---> "   << endl << flush;
                int nBytes = -1;

                std::vector<char> bytes;
                try
                {
                    do// recive all bytes, if the buffer is to small for the whole data
                    {
                        nBytes = socket().receiveBytes(incommingBuffer, sizeof(incommingBuffer));
                        for(int i = 0; i < nBytes; i++)
                        {
                            bytes.push_back(incommingBuffer[i]);
                        }
                    }while(socket().available() > 0);
                }
                catch (Poco::Exception& exc)
                {
                    //Handle your network errors.
                    cerr << "Network error: " << exc.displayText() << endl;
                    isOpen = false;
                }

                if (nBytes==0)
                {
                    cout << "Client closes connection!" << endl << flush;
                    isOpen = false;
                }
                else
                {
                    bytes.push_back('\0');
                    std::string line(&bytes[0]);
                    cout << line << endl;
                    const auto answer = std::string("you send me: ") + line;
                    socket().sendBytes(answer.c_str(),answer.size());
                }
            }
        }
        cout << "Connection finished!" << endl << flush;
    }
};



using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;

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

    ~MyServer()
    {
    }

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
        {
            // get parameters from configuration file
            const auto port = (unsigned short) config().getInt("MyServer.port", 1234);

            //const int port = 1234;
            Poco::Net::ServerSocket svs(port);
            //Configure some server params.
            Poco::Net::TCPServerParams* pParams = new Poco::Net::TCPServerParams();
            pParams->setMaxThreads(4);
            pParams->setMaxQueued(4);
            pParams->setThreadIdleTime(100);

            //Create your server
            Poco::Net::TCPServer myServer(new Poco::Net::TCPServerConnectionFactoryImpl<newConnection>(), svs, pParams);
            cout << "start server on " << svs.address().host().toString() << ":" << svs.address().port() << endl;
            myServer.start();

            waitForTerminationRequest();
        }
        return Application::EXIT_OK;
    }

private:
    bool _helpRequested;
};

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

python 3中的客户端代码

import socket

TCP_IP = '127.0.0.1'
TCP_PORT = 1234
BUFFER_SIZE = 1024
message = "Hello, World!"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
try:
    message = input()
    while message != "quit":
        s.send(message.encode('utf-8'))
        #data = s.recv(BUFFER_SIZE)
        #print(data.decode('utf-8'))
        message = input()

except BaseException:
    pass

s.close()

有人知道为什么会这样吗?

我使用的是MacOS X和poco 1.7.5

问候 通卡

1 个答案:

答案 0 :(得分:1)

我知道这是一个老问题,无论如何,我发现该问题与以下设置有关:pParams->setThreadIdleTime(100);

请注意,这是我对发生的情况的猜测:

  1. setThreadIdleTime需要Poco :: Timespan作为参数
  2. 具有单个参数的Poco :: Timespan构造函数存在,并且需要微秒数(“转换构造函数”)
  3. TcpServerDispatcher使用totalMilliseconds作为空闲时间
 void TCPServerDispatcher::run() {
     ...
     int idleTime = (int) _pParams->getThreadIdleTime().totalMilliseconds(); `