使用 Boost.Asio 的简单服务器抛出异常
Simple server using Boost.Asio throws an exception
我正在尝试使用 Boost.Asio 库编写一个简单的服务器。我希望我的服务器从客户端接收消息并在控制台上打印该消息。这是我的服务器程序的代码:
#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;
}
这是我的客户端程序的代码:
#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;
}
但是当我启动客户端时,服务器抛出异常"read access violation"。我做错了什么?
您正在使用 enable_shared_from_this
,但没有任何东西可以让您的 Session 保持活动状态,因为您只使用 unique_ptr<Session>
.
这意味着您的 Session 在 运行 操作期间消失。
修复它:
std::make_shared<Session>(std::move(socket))->start();
接下来,在您的完成处理程序中保存一个共享指针:
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();
});
}
接下来,如果出现错误(否则您的会话将无限循环),则切断异步循环:
socket_.async_read_some(buffer(data_), [this, self](error_code errorCode, size_t length) {
if (!errorCode && length) {
std::cout << "received: " << data_ << std::endl;
start();
}
});
最后,调整缓冲区大小,以便您可以实际接收数据 (!):
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();
}
});
还有一些问题,但是嘿,程序不会立即崩溃,你有 一些 结果。
更新
添加了显示更多建议的现场演示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 库编写一个简单的服务器。我希望我的服务器从客户端接收消息并在控制台上打印该消息。这是我的服务器程序的代码:
#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;
}
这是我的客户端程序的代码:
#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;
}
但是当我启动客户端时,服务器抛出异常"read access violation"。我做错了什么?
您正在使用 enable_shared_from_this
,但没有任何东西可以让您的 Session 保持活动状态,因为您只使用 unique_ptr<Session>
.
这意味着您的 Session 在 运行 操作期间消失。
修复它:
std::make_shared<Session>(std::move(socket))->start();
接下来,在您的完成处理程序中保存一个共享指针:
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();
});
}
接下来,如果出现错误(否则您的会话将无限循环),则切断异步循环:
socket_.async_read_some(buffer(data_), [this, self](error_code errorCode, size_t length) {
if (!errorCode && length) {
std::cout << "received: " << data_ << std::endl;
start();
}
});
最后,调整缓冲区大小,以便您可以实际接收数据 (!):
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();
}
});
还有一些问题,但是嘿,程序不会立即崩溃,你有 一些 结果。
更新
添加了显示更多建议的现场演示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();
}
}