Boost tcp_server async_write 错误:访问冲突写入位置

Posted

技术标签:

【中文标题】Boost tcp_server async_write 错误:访问冲突写入位置【英文标题】:Boost tcp_server async_write error: access violation writing location 【发布时间】:2014-08-25 14:37:21 【问题描述】:

我一直在尝试使用 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->write("Some Text") ,但是 async_write 引发和异常说“访问冲突写入位置”。我相信可能有一些对象在它应该被清理之前被清理了,但我不明白为什么以及在哪里,所以如果有人能给我一些关于为什么会发生这种情况以及如何解决它的见解,我将不胜感激。

提前感谢您的帮助。

【问题讨论】:

您从哪里调用server-&gt;write() 方法?您的 SetupServer 方法在本地声明 io_service。一旦超出范围,所有使用该 io_service 的套接字/连接/操作都将是未定义的行为。 @DaveS 你是绝对正确的,我只是在几分钟前把我的头撞到墙上几次后才发现:) 为了解决这个问题,我使用 new 显式创建了 io_service 变量,以便范围更改时未释放内存,并且一切正常。我将发布我找到的解决方案作为答案,希望它可以在将来对某人有所帮助。 【参考方案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;

希望这可能对某人有所帮助。

【讨论】:

在使用 boost::asio 时,您应该考虑在原始指针上使用 smart_ptr,尤其是在将指针传递给处理程序时。这将使您的生活更轻松,并且应该防止内存泄漏(但也要注意循环)【参考方案2】:

听起来您正在从主线程调用 server->write("Some Text") 。但是,在该时间点,到目前为止可能没有连接任何客户端,因此您可能会尝试在没有连接端点的套接字上写入。甚至可能 io_service 线程还没有启动。

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

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

【讨论】:

以上是关于Boost tcp_server async_write 错误:访问冲突写入位置的主要内容,如果未能解决你的问题,请参考以下文章

tcp_server_协程gevent版本

远程执行命令

粘包2

python-利用socket客户端服务端循环收发消息

enabled_shared_from_this 如何影响 shared_ptr 的生命周期?

利用tcp协议实现远程控制