boost :: Asio写作大小的悬挂

boost::asio write hangs for large sizes

本文关键字:Asio boost      更新时间:2023-10-16

我正在使用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();
    }
}

所以grep_impl在结果中放了一个大字符串。精确的38MB - Rahul Mahadev 18小时前

因此,在回应该评论时:您只阅读BUF_SIZE字符。

(请注意,这仍然不会导致写信,因为写操作只会在连接通过对等重置时停止,您在send_request客户端中有一个明确的socket.close())。 <</em>

读取更大的响应(我假设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数据:

活在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