繁体   English   中英

连接到Boost.Asio创建的域套接字时,权限被拒绝

[英]Permission refused when connecting to domain socket created by Boost.Asio

我正在尝试创建一个通过域套接字接收连接的服务器。 我可以启动服务器,并且可以看到在文件系统上创建了套接字。 但是每当我尝试通过socat连接到它时,都会出现以下错误:

2015/03/02 14:00:10 socat[62720] E connect(3, LEN=19 AF=1 "/var/tmp/rpc.sock", 19): Connection refused

这是我的Asio代码(仅.cpp文件)。 尽管有帖子标题,但我使用的是Asio的无Boost版本,但我认为这不是问题。

namespace myapp {

  DomainListener::DomainListener(const string& addr) : socket{this->service}, Listener{addr} {
    remove(this->address.c_str());
    stream_protocol::endpoint ep(this->address);
    stream_protocol::acceptor acceptor(this->service, ep);
    acceptor.async_accept(this->socket, ep, bind(&DomainListener::accept_callback, this, _1));
  }

  DomainListener::~DomainListener() {
    this->service.stop();
    remove(this->address.c_str());
  }

  void DomainListener::accept_callback(const error_code& ec) noexcept {
    this->socket.async_read_some(asio::buffer(this->data), bind(&DomainListener::read_data, this, _1, _2));
  }

  void DomainListener::read_data(const error_code& ec, size_t length) noexcept {
    //std::cerr << "AAA" << std::endl;
    //std::cerr << this->data[0] << std::endl;
    //std::cerr << "BBB" << std::endl;
  }

} 



Listener::Listener(const string& addr) : work{asio::io_service::work(this->service)} {
    this->address = addr;
  }

  void Listener::listen() {
    this->service.run();
  }

  Listener::~Listener() {
  }

在使用这些类的代码中,每当我要开始侦听套接字的连接时,就调用listen()

我设法使它与libuv一起使用并更改为Asio,因为我认为这样做会使代码更具可读性,但是我发现文档非常含糊。

问题很可能是acceptor的寿命。

acceptorDomainListener构造函数中的一个自动变量。 DomainListener构造函数完成后, acceptor被销毁,导致接收器关闭并取消未完成的操作,例如async_accept操作。 将向取消的操作提供错误代码asio::error::operation_aborted并计划在io_service进行延迟调用。 因此,尝试连接到域套接字时可能没有活动的侦听器。 有关影响IO物件破坏的更多详细信息,请参阅答案。

DomainListener::DomainListener(const string&) : /* ... */
{
  // ...
  stream_protocol::acceptor acceptor(...);
  acceptor.async_accept(..., bind(accept_callback, ...));
} // acceptor destroyed, and accept_callback likely cancelled

要解决此问题,请考虑通过将acceptor成为DomainListener的数据成员来DomainListener acceptor的寿命。 此外,检查提供给异步操作的error_code可以提供对异步调用链的更多了解。


这是一个完整的最小示例, 演示了如何将域套接字与Asio一起使用。

#include <cstdio>
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

/// @brief server demonstrates using domain sockets to accept
///        and read from a connection.
class server
{
public:
  server(
    boost::asio::io_service& io_service,
    const std::string& file)
    : io_service_(io_service),
      acceptor_(io_service_, 
        boost::asio::local::stream_protocol::endpoint(file)),
      client_(io_service_)
  {
    std::cout << "start accepting connection" << std::endl;
    acceptor_.async_accept(client_,
      boost::bind(&server::handle_accept, this,
        boost::asio::placeholders::error));
  }

private:

  void handle_accept(const boost::system::error_code& error)
  {
    std::cout << "handle_accept: " << error.message() << std::endl;
    if (error) return;

    std::cout << "start reading" << std::endl;
    client_.async_read_some(boost::asio::buffer(buffer_),
      boost::bind(&server::handle_read, this,
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));
  }

  void handle_read(
    const boost::system::error_code& error,
    std::size_t bytes_transferred)
  {
    std::cout << "handle_read: " << error.message() << std::endl;
    if (error) return;

    std::cout << "read: ";
    std::cout.write(buffer_.begin(), bytes_transferred);
    std::cout.flush();
  }

private:
  boost::asio::io_service& io_service_;
  boost::asio::local::stream_protocol::acceptor acceptor_;
  boost::asio::local::stream_protocol::socket client_;
  std::array<char, 1024> buffer_;
};

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

  // Remove file on startup and exit.
  std::string file(argv[1]);
  struct file_remover
  {
    file_remover(std::string file): file_(file) { std::remove(file.c_str()); }
    ~file_remover() { std::remove(file_.c_str()); }
    std::string file_;
  } remover(file);

  // Create and run the server.
  boost::asio::io_service io_service;
  server s(io_service, file);
  io_service.run();
}

Coliru没有安装socat,因此以下命令使用OpenBSD netcat将“ asio域套接字示例”写入域套接字:

export SOCKFILE=$PWD/example.sock
./a.out $SOCKFILE &
sleep 1
echo "asio domain socket example" | nc -U $SOCKFILE

哪个输出:

start accepting connection
handle_accept: Success
start reading
handle_read: Success
read: asio domain socket example

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM