boost asio tcp 连接重新连接并读取后没有收到数据

问题描述 投票:0回答:1

我正在使用 boost asio 连接到 TCP 服务器。 当我运行代码时,它在启动后工作正常。我发送请求并得到响应。 当我关闭 tcp 服务器(它是一个设备)时,我遇到超时,并且当我遇到超时时,来自 boost 的 async_read 内部的回调将永远不会被执行。然后我关闭套接字。打开设备后,可以重新建立连接,但接收到的缓冲区大小为 0 字节。我认为那是因为 async_read 在超时后没有正确完成。

标题

#include <iostream>
#include <boost/format.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <chrono>
#include <thread>
#include <future>
#include <sstream>
#include <iomanip>


class TcpClient{
    public:
        int connect(boost::asio::ip::tcp::socket &socket, boost::asio::ip::tcp::endpoint &endpoint);
        int writeAndRead(boost::asio::ip::tcp::socket &socket);

};

这是代码

#include "tcpclient.h"

int TcpClient::connect(boost::asio::ip::tcp::socket &socket, boost::asio::ip::tcp::endpoint &endpoint)
{
    boost::system::error_code error;
    socket.connect(endpoint, error);
    if (!error)
    {
        std::cout << "connected" << std::endl;
        return 1;
    }
    else
    {
        std::cout << "not connected" << std::endl;
        return 0;
    }
}

int TcpClient::writeAndRead(boost::asio::ip::tcp::socket &socket)
{

    boost::system::error_code error;
    auto status = std::async(std::launch::async, [&]()
                             { boost::asio::write(socket, boost::asio::buffer("mytext"), error); })
                      .wait_for(std::chrono::milliseconds{1000});

    switch (status)
    {
    case std::future_status::deferred:
        std::cout << "std::future_status::deferred" << std::endl;
        return 0;
    case std::future_status::ready:
        std::cout << "write success" << std::endl;
        break;
    case std::future_status::timeout:
        std::cout << "std::future_status::timeout" << std::endl;
        return 0;
    }
    boost::asio::streambuf receive_buffer;
    boost::optional<boost::system::error_code> read_result;
    boost::optional<boost::system::error_code> timer_result;
    boost::asio::deadline_timer timer(socket.get_io_service());

    timer.expires_from_now(boost::posix_time::seconds(2));

    timer.async_wait([&timer_result](const boost::system::error_code &error)
                     {
        if (error != boost::asio::error::operation_aborted)
        {
            timer_result = error;
        } });

    boost::asio::async_read(socket,
                            receive_buffer,
                            boost::asio::transfer_at_least(1),
                            [&read_result](const boost::system::error_code &ec, std::size_t bytes_transferred)
                            {
                                std::cout << "read_result: " << read_result << std::endl;
                                read_result = ec;
                            });
    boost::system::error_code ec;

    while (1)
    {
        socket.get_io_service().reset();
        int numHandlers = socket.get_io_service().poll_one(ec);
        if (read_result)
        {
            timer.cancel();
            break;
        }
        else if (timer_result)
        {
            timer.cancel();
            std::cout << "timeout" << std::endl;
            return 0;
        }
    }
    if (receive_buffer.size() == 0)
    {
        std::cout << "receive_buffer size 0" << std::endl;
        return 0;
    }
    std::string rawResponse = boost::asio::buffer_cast<const char *>(receive_buffer.data());
    std::cout << "rawResponse: " << rawResponse << std::endl;
    return 1;
}

int main()
{
    std::string ipAddress = "192.168.2.4";
    unsigned short port = 50001;
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ipAddress), port);
    boost::asio::io_service ioService;
    boost::asio::ip::tcp::socket socket{ioService};
    bool isSuccess{false};
    bool isConnected{false};
    TcpClient tcpclient = TcpClient();

    while (1)
    {
        if (!isConnected)
        {
            isConnected = tcpclient.connect(socket, endpoint);
        }
        if (isConnected)
        {
            isSuccess = tcpclient.writeAndRead(socket);
            if (!isSuccess)
            {
                std::cout << "failed close socket" << std::endl;
                socket.close();
                isConnected = false;
            }
            else
            {
                std::cout << "success" << std::endl;
            }
        }
        std::cout << "wait for 1 sec" << std::endl;
        std::chrono::seconds dura(1);
        std::this_thread::sleep_for(dura);
    }

    return 0;
}

这是输出

success
wait for 1 sec
write success
read_result: 0
rawResponse: 0;

success
wait for 1 sec
write success
timeout
failed close socket
wait for 1 sec
not connected
wait for 1 sec
not connected
wait for 1 sec
not connected
wait for 1 sec
not connected
wait for 1 sec
connected
write success
read_result: 0
receive_buffer size 0
failed close socket
wait for 1 sec
connected
write success
read_result: 0
receive_buffer size 0
failed close socket
c++ boost tcp boost-asio tcpclient
1个回答
0
投票

Asio是一个异步IO库。

您正在使用带有 std::async 的阻塞 API 来...假异步 IO。我建议不要这样做。看起来您的代码是基于(非常)旧的示例代码。

get_io_service()
早已不复存在,
io_service
本身仅作为已弃用 API 的一部分提供。

我不知道你可以访问什么编译器,但这就是我现在编写相同代码的方式:

住在Coliru

#include <boost/asio.hpp>
#include <boost/asio/experimental/awaitable_operators.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
using Socket = asio::use_awaitable_t<>::as_default_on_t<tcp::socket>;
using namespace std::chrono_literals;
using namespace asio::experimental::awaitable_operators;

asio::awaitable<void> delay(std::chrono::steady_clock::duration dur) {
    auto ex = co_await asio::this_coro::executor;
    co_await asio::steady_timer(ex, dur).async_wait(asio::deferred);
}

asio::awaitable<void> requestLoop(Socket& socket) {
    for (std::string request = "test", response;;) {
        if (auto r = co_await (async_write(socket, asio::buffer(request)) || delay(1s)); r.index()) {
            std::cout << "write timeout" << std::endl;
            break;
        }

        auto r = co_await ( //
            asio::async_read(socket, asio::dynamic_buffer(response), asio::transfer_at_least(1),
                             as_tuple(asio::use_awaitable)) ||
            delay(2s));
        if (r.index()) {
            std::cout << "read timeout" << std::endl;
            break;
        }

        auto [ec, bytes] = get<0>(r);

        std::cout << "Response: " << quoted(response) << " (" << ec.message() << ")" << std::endl;
    }
}

asio::awaitable<void> client(std::string ipAddress, uint16_t port) {
    auto ex = co_await asio::this_coro::executor;
    for (;; co_await delay(1s)) {
        try {
            Socket socket(ex);
            co_await socket.async_connect({asio::ip::address::from_string(ipAddress), port});
            std::cout << "Connected to " << socket.remote_endpoint() << std::endl;

            co_await requestLoop(socket);
        } catch (boost::system::system_error const& se) {
            std::cout << "Error: " << se.code().message() << std::endl;
        }
    }
}

int main() {
    asio::io_context ioc;
    //co_spawn(ioc, client("192.168.1.1", 8045), asio::detached);
    co_spawn(ioc, client("0.0.0.0", 8045), asio::detached);
    ioc.run();
}

本地演示:

© www.soinside.com 2019 - 2024. All rights reserved.