c++ - 无法使简单的 boost 网络示例正常工作,仅仅初始化服务器会立即导致错误

标签 c++ boost boost-asio

我正在运行 Xubuntu 14.04 和 Boost 1.54.0。我修改了 this book 中的第 4 章示例能够在客户端和服务器之间发送任意字符串,但现在程序立即失败。

这是服务器:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <string>

using namespace boost::asio;

io_service service;
size_t read_complete(
        char* buff, const boost::system::error_code& err, size_t bytes)
{
    if (err) {
        return 0;
    }
    bool found = std::find(buff, buff + bytes, '\n') < buff + bytes;
    return found? 0 : 1;
}

void handle_connections() {
    ip::tcp::acceptor acceptor(
            service, ip::tcp::endpoint(ip::tcp::v4(), 8001));
    std::string buff;
    while (true) {
        ip::tcp::socket sock(service);
        acceptor.accept(sock);
        int bytes = read(sock, buffer(buff.c_str()), bind(read_complete, buff, _1, _2));
        std::string msg(buff, bytes);
        sock.write_some(buffer(msg));
        sock.close();
    }
}

int main(int argc, char* argv[]) {
    handle_connections();
}

它是直接从书中复制的,并且已经过验证可以正常工作。

这是重现问题所需的最小客户端:

#include <memory>

#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>

using namespace boost::asio;

class Client
{
    public:
        Client(const std::string& server, const std::string& port):
                server(server), port(port)
        {
            service = std::unique_ptr<io_service>(new io_service);
            endpoint = std::unique_ptr<ip::tcp::endpoint>(new ip::tcp::endpoint(
                    ip::address::from_string(server), atoi(port.c_str())));
            boostSocket = std::unique_ptr<ip::tcp::socket>(
                    new ip::tcp::socket(*service));
            std::cout << std::boolalpha << boostSocket.is_open();  // "false"
        }

    private:
        std::string server;
        std::string port;
        std::unique_ptr<io_service> service;
        std::unique_ptr<ip::tcp::socket> boostSocket;
        std::unique_ptr<ip::tcp::endpoint> endpoint;
};

int main()
{
    Client client("127.0.0.1", "8001");
    return 0;
}

运行这个程序告诉我套接字从未打开。所以我深入研究了 GDB 并发现了这个。为方便起见,我省略了在每组行之间使用的 (gdb) s 调试命令。

Client::Client (this=0x7fffffffd7f8, server="127.0.0.1", port="8001")
    at DIRECTORY WHERE I STORED THE CPP FILE:14
14      service = std::unique_ptr<io_service>(new io_service);
    boost::asio::io_service::io_service (this=0x622130) at /usr/include/boost/asio/impl/io_service.ipp:41
41  {
    boost::asio::detail::noncopyable::noncopyable (this=0x622130) at /usr/include/boost/asio/detail/noncopyable.hpp:29
29    noncopyable() {}
    boost::asio::io_service::io_service (this=0x622130) at /usr/include/boost/asio/impl/io_service.ipp:39
39          (std::numeric_limits<std::size_t>::max)())),
    std::numeric_limits<unsigned long>::max () at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/limits:1196
1196          max() _GLIBCXX_USE_NOEXCEPT { return __LONG_MAX__ * 2UL + 1; }
    boost::asio::io_service::io_service (this=0x622130) at /usr/include/boost/asio/impl/io_service.ipp:41
41  {
    boost::asio::detail::service_registry::service_registry<boost::asio::detail::task_io_service, unsigned long> (this=0x622150, o=..., arg=18446744073709551615)
    at /usr/include/boost/asio/detail/impl/service_registry.hpp:29
29  {
    boost::asio::detail::noncopyable::noncopyable (this=0x622150) at /usr/include/boost/asio/detail/noncopyable.hpp:29
29    noncopyable() {}
    boost::asio::detail::posix_mutex::posix_mutex (this=0x622158) at /usr/include/boost/asio/detail/impl/posix_mutex.ipp:33
33  {
    boost::asio::detail::noncopyable::noncopyable (this=0x622158) at /usr/include/boost/asio/detail/noncopyable.hpp:29
29    noncopyable() {}
    boost::asio::detail::posix_mutex::posix_mutex (this=0x622158) at /usr/include/boost/asio/detail/impl/posix_mutex.ipp:34
34    int error = ::pthread_mutex_init(&mutex_, 0);

相关行是第一行(因为它是我代码的一部分)和最后一行(它直接进入错误处理)。随后的 GDB 命令仅表明它进一步深入了 Boost 的错误处理系统。为什么?我所做的只是创建一个 io_service

最佳答案

我必须修复客户端和服务器程序中的错误才能编译。

这是固定服务器:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <string>

using namespace boost::asio;

io_service service;
size_t read_complete(std::vector<char>const& buff, const boost::system::error_code &err, size_t bytes) {
    if (err) {
        return 0;
    }

    auto last = buff.begin()+bytes;
    bool found = (last != std::find(buff.begin(), last, '\n'));
    return found;
}

void handle_connections() {
    ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), 8001));

    std::vector<char> buff(1024);
    while (true) {
        ip::tcp::socket sock(service);
        acceptor.accept(sock);
        int bytes = read(sock, buffer(buff), bind(read_complete, boost::ref(buff), _1, _2));
        sock.send(buffer(buff, bytes));
        sock.close();
    }
}

int main() { handle_connections(); }

有很多更改,最显着的是修复缓冲区的更改。


这是固定客户端。我摒弃了所有对 new 的迷信用法:

#include <memory>

#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>

using namespace boost::asio;

class Client {
  public:
    Client(const std::string &server, const std::string &port) 
        : server(server),
          port(port),
          service(),
          endpoint(ip::address::from_string(server), atoi(port.c_str())),
          boostSocket(service)
    {
        std::cout << std::boolalpha << boostSocket.is_open() << "\n"; // of course, "false"
    }

  private:
    std::string server;
    std::string port;
    io_service service;
    ip::tcp::endpoint endpoint;
    ip::tcp::socket boostSocket;
};

int main() {
    Client client("127.0.0.1", "8001");
    return 0;
}

注意事项:

  • 您应该使用解析器来解析地址/端口,而不是仅仅对转换进行硬编码(它可能不是 IP 或端口号)

  • 你永远不会连接,所以当然套接字没有打开

    boostSocket.connect(endpoint);
    std::cout << std::boolalpha << boostSocket.is_open() << "\n"; // of connected, "true"
    
    /*
     *std::string message("hellow world\n\n\n\n\n");
     *boostSocket.send(buffer(message));
     *streambuf sb;
     *read(boostSocket, sb, boost::asio::transfer_all());
     *std::cout << "RESPONSE: '" << &sb << "'\n";
     */
    

调试愉快

关于c++ - 无法使简单的 boost 网络示例正常工作,仅仅初始化服务器会立即导致错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33252522/

相关文章:

c++ - 如何将 boost visitor 概念与包含状态变量的类一起使用?

c++ - boost 构建 : Use a feature or a variable

c++ - boost::asio::placeholders::bytes_transferred 是什么意思

C++ Boost::ASIO 线程池问题

c++ - 使用 new 并能够检查指针是否为 0(空)

c++ - 如何并排执行两个 QGraphicsViews 的 50/50 布局?

c++ - Poco AsyncChannel 不会在 fork 进程退出时退出

c++ - Linux 应用程序在 boost::thread::join 上卡住

c++ - 如何在静态库中提供默认的 YAML 配置值?

c++ - 使用 Boost Asio 同步 HTTPS POST