开发者

Can I have blocking I/O within an asynchronous io_machine?

I have a server that's currently using asynchronous IO to (1) accept data from cin and send that input across a UNIX socket and (2) accept data on a UNIX socket, parse that data, and send back a response.

When I'm parsing the data, how can I block the I/O that occurs in the parser (ParseJSON(data_.data()) in the example below)? It should ask questions and collect answers to those questions via cin before returning parsed for the async_write; currently, the questions are printed, but the response is sent before the answers are input to cin.

socket_ is a stream_protocol::socket from boost::asio, FWIW.

void handle_read(const boost::system::error_code& error,
                 size_t bytes_transferred)
{
    if (!error)
    {
        string parsed = ParseJSON(data_.data());
        async_write(socket_,
            buffer(parsed),
            boost::bind(&session::handle_write,
                shared_from_this(),
                placeholders::error));
    }
}

void handle_write(const boost::system::error_code& error)
{
    if (!error)
    {
        socket_.async_read_some(buffer(data_),
            boost::bind(&session::handle_read,
                shared_from_this(),
                placeholders::error,
                placeholders::bytes_transferred));
    }
}

An abbreviated version of what开发者_高级运维 happens in ParseJSON (Some strings replaced with <> for confidentiality):

string ParseJSON(string input)
{
    int status;
    string toWrite;

    JSONNode parsed = libjson::parse(input);
    JSONNode::const_iterator iter = parsed.begin(); 
    json_string node_name = iter -> as_string();

    if (node_name.compare("<>") == 0)   
    {
        cout << "<>" << endl;
        cout << "<>";
        cout.flush();
        cin >> status;

        JSONNode n(JSON_NODE);
        n.push_back(JSONNode("<>","<>"));
        JSONNode c(JSON_NODE);
        c.set_name("args");
        c.push_back(JSONNode("<>",status));
        n.push_back(c);
        toWrite = n.write();
        return toWrite;
    }
}


If ParseJSON() does a blocking read from cin then it will block which means that handle_read() won't execute the async_write() until ParseJSON() returns.

I think the problem is that parsed is a stack variable. handle_read() will most likely return before the data is actually written and parsed will be destroyed. The data passed to async_write() needs to be valid until the completion handler (handle_write) is called.

If handle_read() and and handle_write() are member functions you could add a parsed member to hold the data. Alternatively, you could wrap parsed in shared_ptr that is bound to handle_write() something like this:

void handle_read(const boost::system::error_code& error,
                 size_t bytes_transferred)
{
    if (!error)
    {
        string *ps = new string(ParseJSON(data_.data()));
        boost::shared_ptr<string> pParsed(ps);
        async_write(socket_,
            buffer(*pParsed),
            boost::bind(&session::handle_write,
                shared_from_this(),
                pParsed,
                placeholders::error));
    }
}

void handle_write(boost::shared_ptr<string> pParsed, 
                  const boost::system::error_code& error)
{
    if (!error)
    {
        socket_.async_read_some(buffer(data_),
            boost::bind(&session::handle_read,
                shared_from_this(),
                placeholders::error,
                placeholders::bytes_transferred));
    }
}

When the completion handler exits, the last reference to the shared_ptr will disappear and ps will be destroyed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜