我修改了boost.asio官方网页上的一个unix套接字回显服务器示例,并采用它来使用协程。
我想让这个服务器同时处理多个连接。一个解决方案是从后台线程运行类会话中的start方法,但我更喜欢协同程序,所以我尝试在单独的spawn中运行每个侦听器。
注意,在方法server::start
中,当我只尝试一个侦听器时,它可以工作,但是对于多个套接字,它不能工作。也许有人能告诉我哪里出错了?谢谢!
#include <cstdio>
#include <iostream>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>
using namespace std::chrono_literals;
constexpr auto kTimeout = 1s;
#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
using boost::asio::local::stream_protocol;
using boost::asio::io_context;
class session: public boost::enable_shared_from_this<session>
{
public:
session(boost::asio::io_context& io_context)
: socket_(io_context),
timer_(io_context)
{
}
stream_protocol::socket& socket()
{
return socket_;
}
void start(const boost::asio::yield_context &yield)
{
while (1) {
auto bytes_read = boost::asio::async_read(socket_, boost::asio::buffer(data_, sizeof(data_)),
boost::asio::transfer_all(), yield);
//timer wait to simulate data processing
timer_.expires_after(kTimeout);
timer_.async_wait(yield);
auto bytes_transferred = boost::asio::async_write(socket_,
boost::asio::buffer(data_, bytes_read),
yield);
}
}
private:
// The socket used to communicate with the client.
stream_protocol::socket socket_;
// Buffer used to store data received from the client.
boost::array<char, 256> data_;
boost::asio::steady_timer timer_;
};
typedef boost::shared_ptr<session> session_ptr;
class server
{
public:
server(boost::asio::io_context& ioc, const std::string& file)
: io_context_(ioc),
strand_(io_context_.get_executor()),
acceptor_(strand_, stream_protocol::endpoint(file))
{
for (int i=0 ; i < 3; i++) {
boost::asio::spawn(strand_,
[this](const boost::asio::yield_context &yield) {
session_ptr new_session(new session(this->io_context_));
try {
acceptor_.async_accept(new_session->socket(), yield);
new_session->start(yield);
} catch (std::exception &e) {
std::cout << "new connection needed: " << e.what() << std::endl;
}
});
}
}
private:
boost::asio::io_service& io_context_;
boost::asio::strand<io_context::executor_type> strand_;
stream_protocol::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: stream_server <file>\n";
std::cerr << "*** WARNING: existing file is removed ***\n";
return 1;
}
boost::asio::io_context ioc;
std::remove(argv[1]);
server s(ioc, argv[1]);
ioc.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
# error Local sockets not available on this platform.
#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
字符串
1条答案
按热度按时间nwwlzxa71#
你只需要运行1个accept,然后只在**之后生成会话。
更好的是,您可以使用
async_accept
的重载来移动套接字,并指定会话的串:您不需要所有会话共享保护服务器/接受器的同一串。而不是一个计数循环,只是chain_accepts:
字符串
您会注意到,为了简化,我更改了其他一些内容:Live On Coliru
型
但是,再多一点!
整个
shared_ptr
业务现在只是不必要的复杂化。毕竟你有一个完整的科罗框架,可以让对象保持活动。事实上,对象只不过是套接字和缓冲区。只要让Session
成为一个科罗:Live型
与
型
旁注
另外,请记住,
async_read
已经默认为transfer_all
。您的方法可能是好的,如果您需要256字节的“消息”。但是,这对我来说不像是“回声服务器”。在实践中,我会
read_some
:型
最后,您需要处理tcp,因为它可能会部分成功:
型