使用pion-net c ++的HTTP客户端请求响应

时间:2013-01-30 09:57:50

标签: c++ http boost-asio pion-net

我想用pion-net创建一个简单的HTTPClient(Pion-net利用boost :: asio。)。
启动版本1.49 Pion-net版本4.11

我的客户应该能够:

  • 发送HTTP请求(这是有效的)
  • 收到HTTP响应(不工作)
  • 异步代码不是必须的,同步就可以了

这就是我得到的:

#include <iostream>
#include "boost/asio.hpp"
#include "boost/thread.hpp"
#include "pion/net/HTTPRequestWriter.hpp"
#include "pion/net/HTTPResponseReader.hpp"


void FinishedResponseReading(pion::net::HTTPResponsePtr httpResponsePtr,
                             pion::net::TCPConnectionPtr tcpConnectionPtr,
                             const boost::system::error_code& errorCode_ref)
{
    // ***************************
    // this code is never reached!
    // ***************************
    std::cout << errorCode_ref << std::endl;
    std::cout << httpResponsePtr->getContent() << std::endl;

    tcpConnectionPtr->finish();
    tcpConnectionPtr->close();
}


void FinishedRequestSending(const boost::system::error_code& error_code_ref,
                            pion::net::TCPConnectionPtr tcpConnectionPtr,
                            pion::net::HTTPRequest* httpRequest_ptr)
{
    // ***************************
    // this code is never reached!
    // ***************************
    pion::net::HTTPResponseReader::FinishedHandler fh =
        boost::bind(FinishedResponseReading, _1, _2, _3);
    pion::net::HTTPResponseReaderPtr httpResponseReaderPtr =
        pion::net::HTTPResponseReader::create(tcpConnectionPtr,
                                              *httpRequest_ptr,
                                              fh);
    httpResponseReaderPtr->receive();
}


int main()
{
    boost::asio::io_service io_service;

    // create and configure HTTPRequest
    pion::net::HTTPRequest* httpRequest_ptr = new pion::net::HTTPRequest();
    pion::net::HTTPRequestPtr httpRequestPtr(httpRequest_ptr);
    httpRequest_ptr->setResource("/someService");
    httpRequest_ptr->setMethod("PUT");

    // create TCPConnection
    pion::net::TCPConnection* tcpConnection_ptr =
        new pion::net::TCPConnection(io_service);
    pion::net::TCPConnectionPtr tcpConnectionPtr(tcpConnection_ptr);

    // create HTTPRequestWriter
    pion::net::HTTPRequestWriterPtr httpRequestWriterPtr(
        pion::net::HTTPRequestWriter::create(tcpConnectionPtr,
                                             httpRequestPtr,
                                             boost::bind(FinishedRequestSending, _1,
                                                         tcpConnectionPtr, 
                                                         httpRequest_ptr)));
    // needed?
    tcpConnection_ptr->setLifecycle(pion::net::TCPConnection::LIFECYCLE_KEEPALIVE);
    // connect to server
    tcpConnection_ptr->connect("192.168.1.14", 8080);
    // send payload
    httpRequestWriterPtr << "{\"someService\": \"something\"}";
    httpRequestWriterPtr->send();

    // ***********************************
    // working fine so far! server is getting payload and is sending a HTTP Response
    // but FinishedRequestSending is never reached
    // ***********************************

    // this is just to not exit immediately
    boost::this_thread::sleep(boost::posix_time::milliseconds(15000));

    // cleanup
    delete(httpRequest_ptr);
    delete(tcpConnection_ptr);

    return 0;
}

3 个答案:

答案 0 :(得分:4)

如果你想同步沟通,你可以这样做:

int main()
{
    boost::asio::io_service io_service
    pion::net::TCPConnection tcpConnection(io_service);

    pion::net::HTTPRequest httpRequest;
    httpRequest.setResource("/server/resource");
    httpRequest.setMethod("PUT");
    httpRequest.setMinor(1);
    httpRequest.setMajor(1);
    httpRequest.setContent("test");

    boost::system::error_code ec;
    ec = tcpConnection.connect("192.168.1.1", 80); // blocks till connected or timed out
    if (!ec)
    {
        httpRequest.send(tcpConnection, ec); // never blocks
        if (!ec)
        {
            pion::net::HTTPResponse(httpRequest);
            httpResponse.receive(tcpConnection, ec); // this might block forever :-(
            // httpResponse.receive seems to be IO dependent, you can set your socket to timeout
            if (!ec)
            {
                httpResponse.write(std::cout, ec);
            }
        }
    }
}

<小时/> 但是,如果你需要更复杂的方法,你可以pion::net::HTTPResponseReader等待asynch进行服务器响应 标题:

class MyHTTPClient {
public:
    void close();
    pion::net::HTTPResponsePtr blockingReceiveOrTimeout(pion::net::HTTPRequest httpRequest, boost::system::error_code& ec_ref);
    MyHTTPClient(boost::asio::ip::address aServerIP, unsigned int aServerPort);
    virtual ~MyHTTPClient();
private:
    boost::asio::ip::address            mp_serverIP;
    unsigned int                    mp_serverPort;
    boost::asio::io_service             mp_ioService;
    pion::net::TCPConnectionPtr         mp_tcpConnectionPtr;
    pion::net::HTTPResponsePtr          mp_curr_httpResponsePtr;
    boost::system::error_code           mp_curr_errorCode;

    void finishedReceiveResponse(pion::net::HTTPResponsePtr httpResponsePtr, const boost::system::error_code& error_code_ref);

};

CPP:

MyHTTPClient::MyHTTPClient(boost::asio::ip::address aServerIP, unsigned int aServerPort) : mp_serverIP(aServerIP), mp_serverPort(aServerPort)
{
    mp_tcpConnectionPtr.reset(new pion::net::TCPConnection(mp_ioService));
    mp_tcpConnectionPtr->setLifecycle(pion::net::TCPConnection::LIFECYCLE_KEEPALIVE);
}

MyHTTPClient::~MyHTTPClient()
{
     mp_tcpConnectionPtr->close();
}

void MyHTTPClient::close()
{
    mp_tcpConnectionPtr->close();
}

pion::net::HTTPResponsePtr MyHTTPClient::blockingReceiveOrTimeout(pion::net::HTTPRequest httpRequest, boost::system::error_code& error_code_ref)
{
    // reinit
    mp_curr_httpResponsePtr.reset();
    mp_ioService.reset();
    error_code_ref.clear();

    // connect to server if not already connectec
    if (!mp_tcpConnectionPtr->is_open())
    {
        error_code_ref = mp_tcpConnectionPtr->connect(mp_serverIP, mp_serverPort);
    }
    if (!error_code_ref)
    {
        // send Request
        httpRequest.send(*mp_tcpConnectionPtr.get(), error_code_ref, false);

        if (!error_code_ref)
        {
            // asynchronously wait for response (times out automatically)
            pion::net::HTTPResponseReader::FinishedHandler responseReaderFinishHandler = boost::bind(&MyHTTPClient::finishedReceiveResponse, this, _1, _3);
            const pion::net::HTTPRequest constHTTPRequest = httpRequest;
            pion::net::HTTPResponseReaderPtr httpResponseReaderPtr = pion::net::HTTPResponseReader::create(
                    mp_tcpConnectionPtr,
                    constHTTPRequest,
                    responseReaderFinishHandler);
             httpResponseReaderPtr->receive();
             mp_ioService.run();
        }
    }
    return mp_curr_httpResponsePtr;
}

void MyHTTPClient::finishedReceiveResponse(pion::net::HTTPResponsePtr httpResponsePtr, const boost::system::error_code& error_code_ref)
{
    mp_curr_httpResponsePtr = httpResponsePtr;
}

答案 1 :(得分:2)

Martin的代码已更新为PION 5.0.3:

httpClient.hpp:

#ifndef httpClient_HPP_INCLUDED
#define httpClient_HPP_INCLUDED

#include <pion/error.hpp>
#include <pion/http/response.hpp>
#include <pion/tcp/connection.hpp>
#include <pion/http/response_reader.hpp>
#include <boost/asio.hpp>

class httpClient
{
public:
    void close();
    pion::http::response_ptr blockingReceiveOrTimeout(pion::http::request httpRequest, boost::system::error_code& ec_ref);
    httpClient(boost::asio::ip::address aServerIP, unsigned int aServerPort);
    virtual ~httpClient();

private:
    boost::asio::ip::address mp_serverIP;
    unsigned int mp_serverPort;
    boost::asio::io_service mp_ioService;
    pion::tcp::connection_ptr mp_tcpConnectionPtr;
    pion::http::response_ptr mp_curr_httpResponsePtr;
    boost::system::error_code mp_curr_errorCode;

    void finishedReceiveResponse(pion::http::response_ptr httpResponsePtr, const boost::system::error_code& error_code_ref);

};

#endif // httpClient_HPP_INCLUDED

httpClient.cpp:

#include "httpClient.hpp"

httpClient::httpClient(boost::asio::ip::address aServerIP, unsigned int aServerPort) : mp_serverIP(aServerIP), mp_serverPort(aServerPort)
{
    mp_tcpConnectionPtr.reset(new pion::tcp::connection(mp_ioService));
    mp_tcpConnectionPtr->set_lifecycle(pion::tcp::connection::LIFECYCLE_KEEPALIVE);
}

httpClient::~httpClient()
{
     mp_tcpConnectionPtr->close();
}

void httpClient::close()
{
    mp_tcpConnectionPtr->close();
}

pion::http::response_ptr httpClient::blockingReceiveOrTimeout(pion::http::request httpRequest, boost::system::error_code& error_code_ref)
{
    // reinit
    mp_curr_httpResponsePtr.reset();
    mp_ioService.reset();
    error_code_ref.clear();

    // connect to server if not already connectec
    if (!mp_tcpConnectionPtr->is_open())
    {
        error_code_ref = mp_tcpConnectionPtr->connect(mp_serverIP, mp_serverPort);
    }
    if (!error_code_ref)
    {
        // send Request
        httpRequest.send(*mp_tcpConnectionPtr.get(), error_code_ref, false);

        if (!error_code_ref)
        {
            // asynchronously wait for response (times out automatically)
            pion::http::response_reader::finished_handler_t responseReaderFinishHandler = boost::bind(&httpClient::finishedReceiveResponse, this, _1, _3);
            const pion::http::request constHTTPRequest = httpRequest;
            pion::http::response_reader_ptr httpResponseReaderPtr = pion::http::response_reader::create(
                    mp_tcpConnectionPtr,
                    constHTTPRequest,
                    responseReaderFinishHandler);
             httpResponseReaderPtr->receive();
             mp_ioService.run();
        }
    }
    return mp_curr_httpResponsePtr;
}

void httpClient::finishedReceiveResponse(pion::http::response_ptr httpResponsePtr, const boost::system::error_code& error_code_ref)
{
    mp_curr_httpResponsePtr = httpResponsePtr;
}

for completness main.cpp:

#include <iostream>
#include "httpClient.hpp"

int main (int argc, char *argv[])
{
    pion::http::request request;
    std::string requestData = "asdf";
    request.set_content(requestData);
    httpClient client(boost::asio::ip::address::from_string("10.1.1.100"), 80);
    pion::http::response_ptr response;
    boost::system::error_code ec;
    response = client.blockingReceiveOrTimeout(request, ec);
    response->write(std::cout, ec);
    return 0;
}

答案 2 :(得分:1)

我对pion-net不熟悉。但是,基于我认为按照命名约定使用的version,快速浏览pion-net代码看起来好像需要在应用程序代码中调用io_service.run()。我发现pion-net明确调用io_service.run()的唯一地方是PionScheduler类型使用的Server类型。