开发网络应用程序,我有一个Connection类来管理在网络上发送和接收消息。我正在使用boost :: asio。
我现在想让Connection类处理通过TCP和本地UNIX流套接字的连接。但是,boost的模板设计让我很困惑。 AFAICT,local :: stream_protocol :: socket和ip :: tcp :: socket之间没有共享的基类。
我如何创建一个封装网络语义的Connection,以便其他代码不必处理使用哪种协议的细节?
即。我想实现类似的东西:
class Connection() {
Connection(ip::tcp::endpoint& ep);
Connection(local::stream_protocol::endpoint& ep);
void send(Buffer& buf);
}
我将如何实现这一目标?
答案 0 :(得分:1)
经过一番思考,我目前的解决方案是使Connection
虚拟的send和recv函数成为Connection
的模板子类,粗略地说:
template <typename Protocol>
class ConnectionImpl : public Connection {
typedef typename Protocol::socket Socket;
typedef typename Protocol::endpoint EndPoint;
Socket _socket;
public:
ConnectionImpl(boost::asio::io_service& ioSvc, const EndPoint& addr)
: Connection(ioSvc), _socket(ioSvc) {
_socket.connect(addr);
}
void trySend() {
// Initiate async send on _socket here
}
void tryRead() {
// Initiate async recv on _socket here
}
}
有没有办法避免需要子类和使用虚函数?
答案 1 :(得分:1)
AFAICT,之间没有共享的基类 local :: stream_protocol :: socket和ip :: tcp :: socket。
有意为所有套接字对象明确没有基类,documentation很好地描述了基本原理
不包括BSD套接字API的不安全且容易出错的方面。对于 例如,使用int来表示所有套接字缺少类型安全性。 Boost.Asio中的套接字表示为每个使用不同的类型 协议,例如对于TCP,可以使用ip :: tcp :: socket,也可以使用UDP 使用ip :: udp :: socket
答案 2 :(得分:1)
请改用boost :: asio:generic :: stream_protocol :: socket。当您调用async_connect()/ connect()时,它将从远程端点提取系列和协议,然后将它们传递给socket()系统调用以创建正确的套接字。
boost::asio::generic::stream_protocol::socket socket_{io_service};
if (use_unix_socket) {
boost::asio::local::stream_protocol::endpoint unix_endpoint{"/tmp/socketpath.sock"};
socket_.async_connect(unix_endpoint, [](boost::system::error_code ec){
}};
}
else {
boost::asio::ip::tcp::endpoint tcp_endpoint{...};
socket_.async_connect(tcp_endpoint, [](boost::system::error_code ec){
}};
}
还有来自boost :: asio :: basic_socket:
的代码template <typename ConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
void (boost::system::error_code))
async_connect(const endpoint_type& peer_endpoint,
BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ConnectHandler.
BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;
if (!is_open())
{
boost::system::error_code ec;
const protocol_type protocol = peer_endpoint.protocol();
if (this->get_service().open(this->get_implementation(), protocol, ec))
{
detail::async_result_init<
ConnectHandler, void (boost::system::error_code)> init(
BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));
this->get_io_service().post(
boost::asio::detail::bind_handler(
BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(
ConnectHandler, void (boost::system::error_code)))(
init.handler), ec));
return init.result.get();
}
}
return this->get_service().async_connect(this->get_implementation(),
peer_endpoint, BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));
}