c++ - Boost::Asio:async_read 的问题

标签 c++ boost-asio

我正在编写一个简单的 ProxyServer 来分析包并将它们发送到另一个服务器实例,例如像这样:

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

它应该在无限循环中运行。 我现在的问题是代理似乎丢失了包裹,有时甚至挂起。 当我添加大量调试信息(写入控制台)时,ProxyServer 是 更稳定。看起来 ProxyServer 太快了.. :-)

我很确定我做错了什么,这是我的 session 类的代码(代码来自 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));
    }
}

对于我的代理类型,我是否需要使用其他方法来代替 async_*? 我正在从我的公司想要重新启动的某个旧项目中移植代码,但使用的是 boost 而不是之前使用的 Winsock 东西。

知道可能是什么问题吗?

旧代码是这样的: 调用accept方法的main方法创建了两个线程

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

线程调用了以下函数:

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);
}

[编辑]: 我试图同时为客户端和 sqlserver 运行 async_read 命令,但现在我总是崩溃,有时在 boost::bind 中,有时在 boost 库的其他部分。

似乎发生的情况是创建了 2 或 3 个连接(3 个 session )。在关闭第一个 session 时,崩溃似乎发生在第二个 session 中。

boost asio 不是 treadsafe 还是我在这里做错了什么 :-) ?

我在这里发布了小 ProxyServer 的代码:

session .h:link

session .cpp:link

server.h: link

服务器.cpp:link

代理服务器.cpp:link

最佳答案

我怀疑正在发生的事情是您的 async_read_some 调用之一正在返回“一些”数据,但不足以让 SQL 服务器满意它已收到完整的请求。您的代码始终遵循 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 的情况。

到目前为止,您编写的代码不会执行与原始代码相同的操作。具体来说,旧代码同时监听两个套接字上的读取。幸运的是,因为您使用的是 ASIO,所以您不需要弄乱线程。只需在两个套接字上同时发出 async_read_some 请求并异步处理它们。

关于c++ - Boost::Asio:async_read 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6225578/

相关文章:

c++ - 使用条件内循环的 OpenMP 调度是否仍然有效?

c++ - 我将如何替换命令提示符上已有的文本? C++

c++ - Boost.Asio 应用程序在创建接受器对象时抛出异常

c++ - Boost.Asio 的可扩展性

c++ - 调用 boost io_service.post 的正确方法

boost asio 网络断开处理

c++ - 在这种情况下如何包含所有 .cpp 和头文件?

c++ - 比较两个 QMap

c++ - 包装任何 API 函数

c++ - 创建用于写入 TCP 套接字的消息