简体   繁体   English

Boost::Asio:async_read 的问题

[英]Boost::Asio : Problem with async_read

I'm writing a simple ProxyServer that analyzes packages and sends them to another server instance, eg something like this:我正在编写一个简单的 ProxyServer 来分析包并将它们发送到另一个服务器实例,例如:

client -> MyProxy -> SQLServer ->客户端 -> MyProxy -> SQLServer ->
client <- MyProxy <- SQLServer <-客户端 <- MyProxy <- SQLServer <-

It should run in an infinite loop.它应该在无限循环中运行。 My problem now is that the proxy seems to loose packages, sometimes it even hangs.我现在的问题是代理似乎丢失了包,有时甚至挂起。 When I add a lot of debug information (which is written to the console), the ProxyServer is much more stable.当我添加大量调试信息(写入控制台)时,ProxyServer 更加稳定。 It seems like the ProxyServer is too fast.. :-)看来 ProxyServer 太快了.. :-)

I'm pretty sure I'm doing something wrong, here is code of my session class (the code is derived from the Boost::Asio examples).我很确定我做错了什么,这是我的 session class 的代码(代码来自 Boost::Asio 示例)。

#include "session.h"

#include <iostream>
using namespace std;

session::session(boost::asio::io_service& io_service)
: socket_(io_service)
, sqlsocket_(io_service)
, io_service_(io_service)
, resolver(io_service)
{
    cout << "session::session()" << endl;
}

session::~session()
{
    cout << "session::~session()" << endl;
    cout << "closing session ..." << endl;
}

tcp::socket& session::socket()
{
    return socket_;
}

void session::start()
{
    cout << "session::start()" << endl;
    cout << "starting session ..." << endl;

    // connect to the sqlserver database
    tcp::resolver::query query("192.168.1.50", "1317");
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
    tcp::endpoint endpoint = *endpoint_iterator;

    sqlsocket_.async_connect(endpoint,
        boost::bind(&session::handle_sqlserver_connect, this,
        boost::asio::placeholders::error, ++endpoint_iterator));

    // TODO: connect to the connector
}

void session::handle_read(const boost::system::error_code& error,
                          size_t bytes_transferred)
{
    cout << "session::handle_read()" << endl;
    if (!error)
    {
        cout << "session::handle_read() (read: " 
             << bytes_transferred << ")"
             << endl;
        boost::asio::async_write(sqlsocket_,
            boost::asio::buffer(data_, bytes_transferred),
            boost::bind(&session::handle_sqlserver_write, this,
            boost::asio::placeholders::error, bytes_transferred));
    }
    else
    {
        delete this;
    }
}

void session::handle_sqlserver_read(const boost::system::error_code& error,
                                    size_t bytes_transferred)
{
    cout << "session::handle_sqlserver_read()" << endl;
    if (!error)
    {
        cout << "session::handle_sqlserver_read() (read: " 
             << bytes_transferred << ")"
             << endl;
        boost::asio::async_write(socket_,
            boost::asio::buffer(data_, bytes_transferred),
            boost::bind(&session::handle_write, this,
            boost::asio::placeholders::error, bytes_transferred));
    }
    else
    {
        delete this;
    }
}

void session::handle_write(const boost::system::error_code& error,
                           size_t bytes_transferred)
{
    static int count = 0;
    cout << ++count << ". session::handle_write()" << endl;
    if (!error)
    {
        cout << "session::handle_write() (read: " 
             << bytes_transferred << ")"
             << endl;
        socket_.async_read_some(boost::asio::buffer(data_, max_length),
            boost::bind(&session::handle_read, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
    else
    {
        delete this;
    }
}

void session::handle_sqlserver_write(const boost::system::error_code& error,
                                     size_t bytes_transferred)
{
    cout << "session::handle_sqlserver_write()" << endl;
    if (!error)
    {
        cout << "session::handle_sqlserver_write() (read: " 
             << bytes_transferred << ")"
             << endl;
        sqlsocket_.async_read_some(boost::asio::buffer(data_, max_length),
            boost::bind(&session::handle_sqlserver_read, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
    else
    {
        delete this;
    }
}

void session::handle_sqlserver_connect(const boost::system::error_code& error,
                                       tcp::resolver::iterator endpoint_iterator)
{
    cout << "session::handle_sqlserver_connect()" << endl;
    if (!error)
    {
        socket_.async_read_some(boost::asio::buffer(data_, max_length),
            boost::bind(&session::handle_read, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
    else if (endpoint_iterator != tcp::resolver::iterator())
    {
        sqlsocket_.close();
        tcp::endpoint endpoint = *endpoint_iterator;
        sqlsocket_.async_connect(endpoint,
            boost::bind(&session::handle_sqlserver_connect, this,
            boost::asio::placeholders::error, ++endpoint_iterator));
    }
}

Do I need to use other methods instead of async_* for my type of proxy?对于我的代理类型,我是否需要使用其他方法而不是 async_*? I'm porting the code from some old project that my company wants to restart again, but with boost instead of the Winsock stuff that was used before.我正在从我的公司想要重新启动的一些旧项目中移植代码,但使用的是 boost 而不是以前使用的 Winsock 东西。

Any idea what could be the problem?知道可能是什么问题吗?

The old code did something like this: The main method with the accept method call created two threads旧代码做了这样的事情:带有accept方法调用的main方法创建了两个线程

CreateThread(0, 0, (LPTHREAD_START_ROUTINE)listenatclient, (LPVOID)cs, 0, 0);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)listenatserver, (LPVOID)cs, 0, 0);

and the threads called the following functions:并且线程调用了以下函数:

void listenatclient(LPVOID connection)
{
    connection_s* cs = (connection_s*)connection;
    char inMessagecli[MSG_SIZE];
    int rcount = 0;

    ...

    do
    {
        memset(inMessagecli, 0, MSG_SIZE);
        rcount = recv((SOCKET)cs->client, inMessagecli, MSG_SIZE, 0);
        if (rcount != SOCKET_ERROR)
        {
            // analyze package
            ...

            send((SOCKET)cs->server, inMessagecli, rcount, 0);
        }
    } while (rcount > 0);
}

void listenatserver(LPVOID connection)
{
    connection_s* cs = (connection_s*)connection;
    char inMessageserv[MSG_SIZE];
    int rcount = 0;

    do
    {
        memset(inMessageserv, 0, MSG_SIZE);
        rcount = recv((SOCKET)cs->server, inMessageserv, MSG_SIZE, 0);
        if (rcount != SOCKET_ERROR)
        {
            send((SOCKET)cs->client, inMessageserv, rcount, 0);         
        }
    } while (rcount > 0);
}

[EDIT]: I tried to run the async_read commands for the client and the sqlserver simultaneously, but now I get crashes all the time, sometimes in boost::bind, sometimes in other parts of the boost library. [编辑]:我尝试同时为客户端和 sqlserver 运行 async_read 命令,但现在我总是崩溃,有时在 boost::bind 中,有时在 boost 库的其他部分。

What seems to happen is that 2 or three conections are created ( 3 sessions).似乎发生的是创建了 2 或 3 个连接(3 个会话)。 While closing the first session, the crash seems to happen in the second session.在关闭第一个 session 时,崩溃似乎发生在第二个 session 中。

Is boost asio not treadsafe or am I doing something terribly wrong here:-)?是 boost asio 不安全还是我在这里做错了什么:-)?

I posted the code for the little ProxyServer here:我在这里发布了小 ProxyServer 的代码:

session.h: link session.h:链接

session.cpp: link session.cpp:链接

server.h: link server.h:链接

server.cpp: link server.cpp:链接

ProxyServer.cpp: link ProxyServer.cpp:链接

I suspect what is happening is that one of your async_read_some calls is returning "some" data, but not enough for the SQL server to be satisfied that it has received a complete request.我怀疑正在发生的事情是您的 async_read_some 调用之一正在返回“一些”数据,但不足以让 SQL 服务器满意它已收到完整的请求。 You code always follows the path of read_from_client -> send_to_server -> read_from_server -> send_to_client.您的代码始终遵循 read_from_client -> send_to_server -> read_from_server -> send_to_client 的路径。 It does not handle the case where you need read_from_client -> send_to_server - >read_from_client -> send_to_server -> read_from_server -> send_to_client.它不处理您需要 read_from_client -> send_to_server ->read_from_client -> send_to_server -> read_from_server -> send_to_client 的情况。

The code you have written so far does not perform the same operations as the original.到目前为止,您编写的代码不会执行与原始代码相同的操作。 Specifically, the old code was simultaneously listening for reads on both sockets.具体来说,旧代码同时监听 sockets 上的读取。 Fortunately, since you're using ASIO, you don't need to mess with threads.幸运的是,由于您使用的是 ASIO,因此您不需要弄乱线程。 Just issue issue simultaneous async_read_some requests on both sockets and deal with them asynchronously.只需在 sockets 上同时发出 async_read_some 请求并异步处理它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM