使用Boost.Asio的简单服务器抛出异常 [英] Simple server using Boost.Asio throws an exception

查看:44
本文介绍了使用Boost.Asio的简单服务器抛出异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Boost.Asio库编写一个简单的服务器.我希望服务器从客户端接收消息,然后在控制台上打印该消息.这是我的服务器程序的代码:

I am trying to write a simple server using Boost.Asio library. I want my server to receive a message from the client and print that message on the console. Here is the code of my server program:

#include <iostream>
#include <string>
#include <memory>

#include <boost/asio.hpp>

using namespace boost::asio;
using namespace boost::system;
using boost::asio::ip::tcp;

class Session : public std::enable_shared_from_this<Session> {
public:
    Session(tcp::socket socket);

    void start();
private:
    tcp::socket socket_;
    std::string data_;
};

Session::Session(tcp::socket socket) : socket_(std::move(socket))
{}

void Session::start()
{
    socket_.async_read_some(buffer(data_), [this](error_code errorCode, size_t length) {
        if (!errorCode) {
            std::cout << "received: " << data_ << std::endl;
        }
        start();
    });
}

class Server {
public:
    Server(io_context& context);
private:
    tcp::acceptor acceptor_;

    void accept();
};

Server::Server(io_context& context) : acceptor_(context, tcp::endpoint(tcp::v4(), 8888))
{
    accept();
}

void Server::accept()
{
    acceptor_.async_accept([this](error_code errorCode, tcp::socket socket) {
        if (!errorCode) {
            std::make_unique<Session>(std::move(socket))->start();
        }
        accept();
    });
}

int main()
{
    boost::asio::io_context context;
    Server server(context);
    context.run();
    return 0;
}

这是我的客户端程序的代码:

And here is the code of my client program:

#include <iostream>
#include <string>

#include <boost/asio.hpp>

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

int main()
{
    io_context context;
    tcp::socket socket(context);
    tcp::resolver resolver(context);
    connect(socket, resolver.resolve("127.0.0.1", "8888"));
    while (true) {
        try {
            std::string data;
            std::cin >> data;
            write(socket, buffer(data));
        } catch (const std::exception& exception) {
            std::cerr << exception.what() << std::endl;
        }
    }
    return 0;
}

但是,当我启动客户端时,服务器会引发异常读取访问冲突".我该怎么办?

But when I start the client, the server throws exception "read access violation". What do I do wrong?

推荐答案

您正在使用 enable_shared_from_this ,但由于您仅使用 unique_ptr< Session> .

You're using enable_shared_from_this and but nothing keeps your Session alive because you only use unique_ptr<Session>.

这意味着您的会话在运行过程中消失了.

This means your Session goes away during running operations.

解决此问题:

std::make_shared<Session>(std::move(socket))->start();

接下来,在完成处理程序中保留一个共享指针:

Next, hold a shared pointer in your completion handler:

void Session::start()
{
    auto self = shared_from_this();
    socket_.async_read_some(buffer(data_), [this, self](error_code errorCode, size_t /*length*/) {
        if (!errorCode) {
            std::cout << "received: " << data_ << std::endl;
        }
        start();
    });
}

接下来,如果发生错误(或会话将无限循环),请剪切异步循环:

Next, CUT the async loop if there is an error (or your session will loop infinitely):

socket_.async_read_some(buffer(data_), [this, self](error_code errorCode, size_t length) {
    if (!errorCode && length) {
        std::cout << "received: " << data_ << std::endl;
        start();
    }
});

最后,调整缓冲区的大小,以便实际上可以接收数据(!):

Finally, resize the buffer so you can actually receive data (!):

data_.resize(32);
socket_.async_read_some(buffer(data_), [this, self](error_code errorCode, size_t length) {
    if (!errorCode) {
        data_.resize(length);
        std::cout << "received: '" << data_ << "'" << std::endl;
        start();
    }
});

还有一些问题,但是,程序不会立即崩溃,并且您会得到一些结果.

There are still some issues left, but hey, the program won't crash immediately and you have some results.

添加了一个实时演示,显示了更多建议在Coliru上直播

Added a live demo showing some more suggestions Live On Coliru

#include <iostream>
#include <string>
#include <memory>

#include <boost/asio.hpp>

using namespace boost::asio;
using namespace boost::system;
using boost::asio::ip::tcp;

class Session : public std::enable_shared_from_this<Session> {
public:
    Session(tcp::socket socket);

    void start();
private:
    tcp::socket socket_;
    boost::asio::streambuf _sb;
};

Session::Session(tcp::socket socket) : socket_(std::move(socket))
{}

void Session::start()
{
    auto self = shared_from_this();
    async_read_until(socket_, _sb, '\n', [this, self](error_code errorCode, size_t /*length*/) {
        std::cout << "completion " << errorCode.message() << "\n";
        if (!errorCode) {
            std::string line;
            {
                std::istream is(&_sb);
                if (getline(is, line)) {
                    std::cout << "received: '" << line << "'" << std::endl;
                }
                start();
            }
        }
    });
}

class Server {
public:
    Server(io_context& context);
private:
    tcp::acceptor acceptor_;

    void accept();
};

Server::Server(io_context& context) : acceptor_(context, tcp::endpoint(tcp::v4(), 8888))
{
    accept();
}

void Server::accept()
{
    acceptor_.async_accept([this](error_code errorCode, tcp::socket socket) {
        if (!errorCode) {
            std::make_shared<Session>(std::move(socket))->start();
        }
        accept();
    });
}

int main(int argc, char**) {
    if (argc>1) {
        io_context context;
        tcp::socket socket(context);
        tcp::resolver resolver(context);
        connect(socket, resolver.resolve("127.0.0.1", "8888"));
        std::string data;
        while (getline(std::cin, data)) {
            try {
                data += '\n';
                write(socket, buffer(data));
            } catch (const std::exception& exception) {
                std::cerr << exception.what() << std::endl;
            }
        }
    } else {
        boost::asio::io_context context;
        Server server(context);
        context.run();
    }
}

这篇关于使用Boost.Asio的简单服务器抛出异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆