提升tcp_server async_write错误:访问违规写入位置

时间:2014-08-25 14:37:22

标签: c++ multithreading boost boost-asio boost-thread

我一直在尝试使用boost实现一个简单的tcp服务器,它接受客户端连接,并通过调用服务器公开的方法将一些信息发送回客户端。

这是我创建的类,基于Boost教程:

#define WIN32_LEAN_AND_MEAN

#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;


#include <ctime>
#include <iostream>
#include <string>

#include "Logger.h"



class tcp_server_connection
    : public boost::enable_shared_from_this<tcp_server_connection>
{
public:
    typedef boost::shared_ptr<tcp_server_connection> pointer;

    static pointer create(boost::asio::io_service& io_service)
    {
        return pointer(new tcp_server_connection(io_service));
    }

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

    void start(string message)
    {
        swap(m, message);

        boost::asio::async_write(socket_, boost::asio::buffer(m),
            boost::bind(&tcp_server_connection::handle_write, shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

private:
    tcp_server_connection(boost::asio::io_service& io_service)
        : socket_(io_service)
    {
        Logger::Log("main.log", "New TCP Server Connection");
    }


    void handle_write(const boost::system::error_code& error,
        size_t bytes_transferred)
    {
        if (error) {
            Logger::Log("main.log", "TCP Server Write Error: ");
        }
    }

    tcp::socket socket_;
    string m;
};

class tcp_server
{
public:
    tcp_server(boost::asio::io_service& io_service, int port)
        : acceptor_(io_service, tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port))
    {
        start_accept();
    }

    void write(string message) {
        connection->start(message);
    }

private:
    void start_accept()
    {
        connection = tcp_server_connection::create(acceptor_.get_io_service());

        acceptor_.async_accept(connection->socket(),
            boost::bind(&tcp_server::handle_accept, this, connection,
            boost::asio::placeholders::error));
    }

    void handle_accept(tcp_server_connection::pointer new_connection,
        const boost::system::error_code& error)
    {
        if (!error)
        {
            Logger::Log("main.log", "TCP Server Accepted Connection");
        }
        else {
            Logger::Log("main.log", "TCP Server Error accepting Connection");
        }
    }

    tcp::acceptor acceptor_;
    tcp_server_connection::pointer connection;
};

我通过使用此方法启动一个线程来启动服务器:

void SetupServer() {
    boost::asio::io_service io_service;
    server = new tcp_server(io_service, serverPort);
    io_service.run();
}
当我想给客户写东西时,我会调用server-&gt; write(“Some Text”),但是 async_write引发和异常说“访问冲突写入位置”。我相信在它应该之前可能会有一些物体被清理干净,但我不明白为什么以及在哪里,所以如果有人可以给我一些有关为什么会发生这种情况以及如何解决它的信息,我将不胜感激。

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

好吧我发现这个问题与io_service变量在范围变化时被释放的事实有关,而且地狱正在崩溃。

要解决此问题,我将setupServer更改为:

io_service = new boost::asio::io_service();
rankingServer = new tcp_server(*io_service, serverPort);
io_service->run();

并使用它在类的其他地方声明变量:

boost::asio::io_service *io_service = NULL;

请记住,需要释放变量,调用

delete io_service;

希望这可以帮助别人。

答案 1 :(得分:0)

听起来你正在从主线程调用server-&gt; write(“Some Text”)。但是,在该时间点,到目前为止还没有客户端连接,因此您可能尝试在没有连接端点的套接字上写入。甚至可能是io_service线程尚未启动的情况。

使用boost asio编写异步程序时,通常会启动异步操作并传递一个处理程序,一旦请求的操作成功(或失败),就会调用该处理程序。那里你可以做出反应,例如链另一个异步动作。 在您的示例中,一旦客户端成功连接,将调用tcp_server :: handle_accept()处理程序,而不设置错误代码。这是调用写入的地方(“Some Text”)。

基于您的问题,在我看来,您想要从io_service线程的“外部”触发写入数据。使用多个线程时请小心。尝试从“主”线程和运行io_service的线程(以及所有异步处理程序)访问数据时,请务必使用适当的锁定。同时注意竞争条件,不要依赖计算机或操作系统的计时或安排。