【问题标题】:boost::asio write hangs for large sizesboost::asio 写挂起大尺寸
【发布时间】:2017-09-17 15:37:37
【问题描述】:

我正在使用 boost::asio 来实现一个 tcp 服务器和客户端。 当文件很大时,我正在使用写入和读取功能,写入挂起并且没有完成。

这是读取的函数

int send_request(std::string &ep_ip, int ep_port, std::string &message, std::string &response) {
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string(ep_ip), ep_port);
    try {
        boost::asio::ip::tcp::socket socket(io_service);
        boost::system::error_code error;
        socket.connect(ep);
        std::vector<char> buf(BUF_SIZE);
        // buf = new std::vector<char>(BUF_SIZE);
        std::copy(message.begin(), message.end(), buf.begin());
        boost::asio::write(socket, boost::asio::buffer(buf), error);
        // int bytes_read = socket.read_some(boost::asio::buffer(buf) , error );
        int bytes_read = boost::asio::read(socket, boost::asio::buffer(buf), error);
        std::copy(buf.begin(), buf.begin() + bytes_read, std::back_inserter(response));
        socket.close();
    } catch (std::exception &e) {
        // std::cerr << e.what() << std::endl;
        return 0;
    }
    return 1;
}

这是写的函数

void listen(int port_no, std::string &filename) {
    boost::asio::io_service io_service;
    std::string result = "";
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port_no));
    while (1) {
        tcp::socket socket(io_service);
        std::vector<char> buf(BUF_SIZE);
        boost::system::error_code ignored_error, error;
        acceptor.accept(socket);
        int req_bytes_read = socket.read_some(boost::asio::buffer(buf), error);
        std::string request;
        std::copy(buf.begin(), buf.begin() + req_bytes_read, std::back_inserter(request));
        request = clean_string(request);
        if (error) {
            std::cout << "[ERROR] Unable to process the request. CODE  " << error << std::endl;
        } else {
            std::cout << "Received the message: " << request << std::endl;
            // This where we do some processing of the request, perhaps call grep.
            std::string PATH = "$HOME/" + filename;
            result = "";
            grep_impl(request, PATH, result);
            // result = grep(request , PATH);
        }
        std::cout << "Size of result is " << result.size() << std::endl;
        boost::asio::write(socket, boost::asio::buffer(result), ignored_error);
        socket.close();
    }
}

【问题讨论】:

  • what 文件的大小?您没有阅读任何文件
  • 所以 grep_impl 在 result 中放入了一个大字符串。准确地说是38mb
  • 我已经更新了我的答案(你为什么不拿示例代码并修改它以显示问题?)

标签: c++ sockets boost boost-asio


【解决方案1】:

所以 grep_impl 在 result 中放入一个大字符串。准确地说是 38mb – Rahul Mahadev 18 小时前

因此,作为对该评论的回应:您只读过BUF_SIZE 个字符。

(请注意,这仍然不会导致写入挂起,因为写入操作将在连接被对等方重置时简单地停止,您在send_request 客户端中有一个明确的socket.close())。

要读取更大的响应(我假设 38mb 更大),您需要一个循环。

while (!error) {
    int bytes_read = ba::read(socket, ba::buffer(buf), error);
    std::copy(buf.begin(), buf.begin() + bytes_read, std::back_inserter(response));
    if (bytes_read == 0)
        break;
}

您可以预期,当服务器停止传输时,错误通常会变为eof

  1. 您发送buf 中的所有字节,即使是那些未填充的字节。我不确定这是故意的,但至少它会破坏输出。

    哦。也许是clean_string 这样做了,但为什么不简单地只发送请求呢?

这是一个使用 1k 缓冲区传输 38mb 数据的独立演示:

Live On Coliru

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

static constexpr size_t BUF_SIZE = 1024u;

namespace ba = boost::asio;
using ba::ip::tcp;

int send_request(std::string const& ep_ip, int ep_port, std::string const& message, std::string &response) {
    ba::io_service io_service;
    tcp::endpoint ep(ba::ip::address::from_string(ep_ip), ep_port);
    try {
        tcp::socket socket(io_service);
        boost::system::error_code error;
        socket.connect(ep);
        std::vector<char> buf(BUF_SIZE);
        std::copy(message.begin(), message.end(), buf.begin());

        ba::write(socket, ba::buffer(buf), error);

        // int bytes_read = socket.read_some(ba::buffer(buf) , error );

        while (!error) {
            int bytes_read = ba::read(socket, ba::buffer(buf), error);
            std::copy(buf.begin(), buf.begin() + bytes_read, std::back_inserter(response));
            if (bytes_read == 0)
                break;
        }

        socket.close();
    } catch (std::exception &e) {
        // std::cerr << e.what() << std::endl;
        return 0;
    }
    return 1;
}

std::string clean_string(std::string const& s) { 
    return s.c_str(); // Cut from NUL
}

void grep_impl(std::string const& /*request*/, std::string const& /*PATH*/, std::string& result) {
    result = std::string(38ul << 20, '*');
}

void listen(int port_no, std::string const& filename) {
    ba::io_service io_service;
    std::string result = "";
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port_no));
    while (1) {
        tcp::socket socket(io_service);
        std::vector<char> buf(BUF_SIZE);
        boost::system::error_code ignored_error, error;
        acceptor.accept(socket);
        int req_bytes_read = socket.read_some(ba::buffer(buf), error);
        std::string request;
        std::copy(buf.begin(), buf.begin() + req_bytes_read, std::back_inserter(request));

        request = clean_string(request);
        if (error) {
            std::cout << "[ERROR] Unable to process the request. CODE  " << error << std::endl;
        } else {
            std::cout << "Received the message: " << request << std::endl;
            // This where we do some processing of the request, perhaps call grep.
            std::string PATH = "$HOME/" + filename;
            result = "";
            grep_impl(request, PATH, result);
            // result = grep(request , PATH);
        }
        std::cout << "Size of result is " << result.size() << std::endl;
        ba::write(socket, ba::buffer(result), ignored_error);
        socket.close();
        break;
    }
}

#include <boost/thread.hpp>

int main() {
    boost::thread_group tg;
    tg.create_thread([]{ listen(6767, "test.cpp"); });
    tg.create_thread([]{ 
            boost::this_thread::sleep_for(boost::chrono::seconds(1));
            std::string response;
            send_request("127.0.0.1", 6767, "TEST", response);

            std::cout << "send_request returned " << response.size() << " bytes";
        });

    tg.join_all();
}

打印

Received the message: TEST
Size of result is 39845888
send_request returned 39845888 bytes

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    相关资源
    最近更新 更多