提升asio io_context.run()分段错误

问题描述 投票:0回答:1

我试图制作简单的服务器,记住并操作一些带有接收短指令的变量。我没有完成这个服务器,我正在尝试测试连接到服务器。但是当我尝试连接服务器时,会发生分段故障。它似乎发生在io_context.run()函数中。尽管阅读了asio的参考页面,但我不知道这个错误的确切原因。请帮我..

我认为你不必阅读数据代码(data.hpp)。这是服务器代码。

//server.cpp
#include <iostream>
#include "network/sc_network.hpp"

int main(int argc, char *argv[])
{
    try
    {
        if(argc != 2)
        {
            std::cerr << "Usage: server <port>\n";
            return 1;
        }

        boost::asio::io_context io_context;

        tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[1]));
        server server(io_context, endpoint);

        io_context.run();

    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }
    return 0;
}

这是客户端代码。

//client.cpp
#include <iostream>
#include <thread>
#include <cstdlib>
#include <boost/asio.hpp>
#include "network/data/data.hpp"

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

class client{
private:
    boost::asio::io_context& io_context_;
    tcp::socket socket_;
    oper_data *data_;

    void do_connect(const tcp::resolver::results_type& endpoints)
    {
        boost::asio::async_connect(socket_, endpoints,
            [this](boost::system::error_code ec, tcp::endpoint)
            {
                if(!ec)
                {
                    boost::asio::async_read(socket_,
                        boost::asio::buffer(data_, sizeof(oper_data)),
                        [this](boost::system::error_code ec, std::size_t)
                        {
                            if(!ec)
                            {
                                boost::asio::async_write(socket_,
                                    boost::asio::buffer(data_,sizeof(oper_data)),
                                    [this](boost::system::error_code ec, std::size_t)
                                    {

                                    });
                            }
                            else
                            {
                                socket_.close();    
                            }
                        });
                }

                else
                {
                    socket_.close();
                }
            });
    }
public:
    client(boost::asio::io_context& io_context,
        const tcp::resolver::results_type& endpoints)
        : io_context_(io_context),
        socket_(io_context) 
    {
        do_connect(endpoints);
    }
    void write(const oper_data& data)
    {
        boost::asio::post(io_context_,
        [this, data]()
        {

        });
    }
};

int main(int argc, char *argv[])
{
    try
    {
        if(argc != 3)
        {
            std::cerr << "Usage: client <host> <port>\n";
            return 1;

        }
        boost::asio::io_context io_context;

        tcp::resolver resolver(io_context);
        auto endpoints = resolver.resolve(argv[1], argv[2]);
        client c(io_context, endpoints);

        std::thread t([&io_context](){ io_context.run(); });

        char line[128];

        while (std::cin.getline(line, 128))
        {
            oper_data data;
            //processing the line with deviding in 3 words.
        }
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

这是sc_network.hpp

//sc_network.hpp
#include <boost/asio.hpp>
#include <memory>
#include <utility>
#include "data/data.hpp"

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

class session
    : public std::enable_shared_from_this<session>
{
private:
    tcp::socket socket_;
    data_proc data_proc_;
public:
    session(tcp::socket socket)
        : socket_(std::move(socket)){}

    void start()
    {
        oper_data *input_data;
        boost::asio::async_read(socket_,
            boost::asio::buffer(input_data, sizeof(oper_data)),
            [this, input_data](boost::system::error_code ec, std::size_t)
            {
                if(!ec)
                {
                    data_proc_.set_data(*input_data);
                    data_proc_.oper_process();
                    start();
                }
                else
                {
                    return;
                }
            });
    }
};

class server
{
private:
    tcp::acceptor acceptor_;

    void do_accept()
    {
        acceptor_.async_accept(
            [this](boost::system::error_code ec, tcp::socket socket)
            {
                if(!ec)
                {
                    session ex_session(std::move(socket));
                }

                do_accept();
            });
    }
public:
    server(boost::asio::io_context& io_context,
        const tcp::endpoint& endpoint)
        : acceptor_(io_context, endpoint)
    {
        do_accept();
    }

};

这是data.hpp。

//data.hpp
#include <deque>
#include <cstring>
#include "favdew_utility.hpp"

#define max_oper_size 5
#define max_oper_buf max_oper_size + 1

struct oper_data {
    char oper_[max_oper_buf] = "\0";
    char *operand_;
    char *oper_num_;
};

typedef struct oper_data oper_data;

class data_store {
private:
    char *var_name_;
    char *var_value_;
public:
    data_store()
        : var_name_(NULL), var_value_(NULL) {}

    data_store(const char *var_name, const char *var_value)
    {
        std::size_t var_name_size = strlen(var_name) + 1;
        var_name_ = new char[var_name_size];
        strncpy(var_name_, var_name, strlen(var_name));

        std::size_t var_value_size = strlen(var_value) + 1;
        var_value_ = new char[var_value_size];
        strncpy(var_value_, var_value, strlen(var_value));
    }
    char *var_name() { return var_name_; }
    char *var_value() { return var_value_; }
    void set_value(const char *var_value) {
        var_value_ = new char[strlen(var_value) + 1];
        strncpy(var_value_, var_value, strlen(var_value));
    }
};

typedef std::deque<data_store> data_queue;

class data_proc {
private:
    oper_data data_;
    data_queue proc_queue;

    void var()
    {
        if (data_store *var = this->get_var(data_.operand_)) {
            var->set_value(data_.oper_num_);
        }
        else {
            data_store input_data(data_.operand_, data_.oper_num_);
            this->proc_queue.push_back(input_data);
        }
    }



    bool sum()
    {
        data_store *var = this->get_var(data_.operand_);
        if ( (var) && isNumber(var->var_value()))
        {
            const int input_data = std::atoi(var->var_value()) +
                std::atoi(this->data_.oper_num_);
            var->set_value(std::to_string(input_data).c_str());
            return true;
        }
        else
            return false;
    }

    bool dif()
    {
        data_store *var = this->get_var(data_.operand_);
        if ((var) && isNumber(var->var_value()))
        {
            const int input_data = std::atoi(var->var_value()) -
                std::atoi(this->data_.oper_num_);
            var->set_value(std::to_string(input_data).c_str());
            return true;
        }
        else
            return false;
    }
public:
    data_proc()
    {
        oper_data input_data;

        //<input_data.oper_> is already initialized with "\0"
        std::memset(input_data.operand_, 0, sizeof(char *));
        std::memset(input_data.oper_num_, 0, sizeof(char *));
    }

    data_proc(const char *oper, const char *operand, const char *oper_num)
    {
        strncpy(data_.oper_, oper, max_oper_size);

        std::size_t operand_size = strlen(operand) + 1;
        data_.operand_ = new char[operand_size];
        strncpy(data_.operand_, operand, strlen(operand));

        std::size_t oper_num_size = strlen(oper_num) + 1;
        data_.oper_num_ = new char[oper_num_size];
        strncpy(data_.oper_num_, oper_num, strlen(oper_num));

    }

    inline void set_data(oper_data data)
    {
        this->data_ = data;
    }

    void set_data(const char *oper, const char *operand, const char *oper_num)
    {
        strncpy(data_.oper_, oper, max_oper_size);

        std::size_t operand_size = strlen(operand) + 1;
        data_.operand_ = new char[operand_size];
        strncpy(data_.operand_, operand, strlen(operand));

        std::size_t oper_num_size = strlen(oper_num) + 1;
        data_.oper_num_ = new char[oper_num_size];
        strncpy(data_.oper_num_, oper_num, strlen(oper_num));
    }

    data_store *get_var(const char *var_name)
    {
        const std::size_t queue_size = this->proc_queue.size();

        for (std::size_t i=0; i < queue_size; i++) {
            if (!strcmp(this->proc_queue[i].var_name(), var_name)) {
                return &proc_queue[i];
            }
        }
        return NULL;
    }


    bool oper_process()
    {
        const char *oper = this->data_.oper_;
        if (!strcmp(oper, "var")) {
            var();
            return true;
        }
        else if (!strcmp(oper, "sum")) {
            sum();
            return true;
        }
        else if (!strcmp(oper, "dif")) {
            dif();
            return true;
        }
        else {
            return false;
        }
    }
};

这是favdew_utility.hpp

#include <string>
#include <cstdlib>

bool isNumber(const char *str)
{
    std::size_t length = strlen(str);

    for (std::size_t i = 0; i < length; i++)
    {
        if (!('0' < str[i] && str[i] < '9'))
            return false;

        continue;
    }
    return true;
}

bool isEmpty(void *buffer)
{
    if (!buffer || *(char *)buffer == '\0')
        return true;
    else
        return false;
}
boost asio
1个回答
1
投票

有很多问题,只需指出几点:

  1. 声明 session ex_session(std::move(socket)); 这将创建一个继承自enable_shared_from_this的本地(堆栈)变量。使用shared_from_this将是Undefined Behaviour 会话立即被破坏,start()似乎从未被调用过
  2. 如果调用session::start(),它将失败,因为它在不保护session实例的生命周期的情况下启动异步操作: boost::asio::async_read(socket_, boost::asio::buffer(input_data, sizeof(oper_data)), [this, input_data](boost::system::error_code ec, std::size_t) { .... 至少你需要捕获到会话的共享指针: auto self = shared_from_this(); boost::asio::async_read(socket_, boost::asio::buffer(input_data, sizeof(oper_data)), [this, self, input_data](boost::system::error_code ec, std::size_t)
  3. 更糟糕的是,input_data从未被初始化。再次:Undefined Behaviour。即使你做了初始化,你也必须管理一生;为什么不让它成为会话的成员,而不是动态分配(或忘记,如你所知)? 警告:不,即使你在lambda中捕获它也不能在start()中进行堆栈分配,因为在start()退出之前异步操作不会完成。
  4. 同样在clientdata_永远不会被初始化。繁荣。
  5. 即使你已正确分配,使用它作为asio::buffer()将其视为POD。 然而,因为data_proc愉快地聚集了一个data_queue,这是std::deque<>,它显然不是POD。更多Undefined Behaviour。 你可能需要的是序列化你的数据结构,而不是希望复制一些字节的内存将神奇地“工作”。它不会! 参见例如sending/receiving a struct in boost::asio 注意当你在,是,使用C ++而不是C?所有的原始指针和char*都是你不需要的复杂性,并且它会递给你几十个脚趾或两端或绳索,你会更加伤害自己。
  6. 在qazxsw poi你有: qazxsw poi 这么多的事情... 使用qazxsw poi,而不是client.cpp 线程需要加入(std::thread t([&io_context](){ io_context.run(); }); char line[128]; while (std::cin.getline(line, 128)) { oper_data data; //processing the line with deviding in 3 words. } ) 如果您只是阻止输入,为什么有线程? std::getline
  7. std::istream::getline也不是POD,但它也是一个活的内存泄漏。所有https://en.cppreference.com/w/cpp/thread/thread/~thread-ed内存永远不会被释放。 请注意,它的编写方式,结构可能看起来是POD,但逻辑上它不是(Rule Of Three)。基本上,你用C语言编写,而不是用C ++编写。这放弃了C ++所有的抽象,现在编译器无法判断结构是指非自有资源。 请注意,这让我觉得 io_context.run(); // replaces all of the above 可能有类似的问题(虽然起初我认为data_storenew应该指向固定大小的缓冲区oper_data

Summarizing:

你领先于自己。开始简单得多。使用C ++(operand_,从不使用_oper_num / oper_[],如果你想使用std::string,实际上使用new)。

你会更开心。当你遇到困难时,请随意回答更简单的问题,理想情况下,SSCCE将是(少数)十几行。

© www.soinside.com 2019 - 2024. All rights reserved.