简体   繁体   English

Boost :: asio :: async_read_until从不调用处理程序

[英]Boost::asio::async_read_until never calls handler

I am trying to build a connection between two computers on a local network, one using a slightly modified version of the Boost Asio C++ TCP asynchronous server sample, the other one using NodeJS. 我正在尝试在本地网络上的两台计算机之间建立连接,一台使用Boost Asio C ++ TCP异步服务器示例的略微修改版本,另一台使用NodeJS。

tcp_client.js : tcp_client.js:

var net = require('net');
var HOST = '127.0.0.1';
var PORT = 14002;

var client = new net.Socket();
client.connect(PORT, HOST, function() {
    console.log('CONNECTED TO: ' + HOST + ':' + PORT);
    // Write a message to the socket as soon as the client is connected
    //the server will receive it as message from the client 
    client.write('Hello');
});

// Add a 'data' event handler for the client socket
// data is what the server sent to this socket
client.on('data', function(data) {
    var fs = require('fs');
    fs.writeFile("test.txt", data, function(err) {
        if(err) {
            return console.log(err);
        }
        client.write("Data written"); // returns successful
        console.log("The file was saved!");
    }); 
});

// Add a 'close' event handler for the client socket
client.on('close', function() {
    console.log('Connection closed');
});

tcpServer.cpp : tcpServer.cpp:

#include <ctime>
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>

extern string _coordinates;

using namespace std;
using boost::asio::ip::tcp;

std::string inline make_daytime_string() {
    std:: time_t now = std::time(0);
    return std::ctime(&now);
}

class tcp_connection
    // Using shared_ptr and enable_shared_from_this
    // because we want to keep the tcp_connection object alive
    // as long as there is an operation that refers to it.
    : public boost::enable_shared_from_this<tcp_connection>
    {
    public:
        typedef boost::shared_ptr<tcp_connection> pointer;

        static pointer create(boost::asio::io_service& io_service) {
            cout << "Creates a pointer for the tcp connection" <<endl;
            return pointer(new tcp_connection(io_service));
        }

        tcp::socket& socket() {
            return socket_;
        }

        // Call boost::asio::async_write() to serve the data to the client.
        // We are using boost::asio::async_write(),
        // rather than ip::tcp::socket::async_write_some(),
        // to ensure that the entire block of data is sent.

        void start() {
            while(1) {
                start_read();

                // This is going to read after every 1ms the _coordinates variable
                usleep(1000);

                m_message = _coordinates;

                boost::asio::async_write(
                    socket_,
                    boost::asio::buffer(m_message),
                    boost::bind(
                        &tcp_connection::handle_write,
                        shared_from_this(),
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
                    )
                );
            }
        }

private:
    tcp_connection(boost::asio::io_service& io_service)
        : socket_(io_service)
        {
        }

    void start_read() {
        // Start an asynchronous operation to read a newline-delimited message.
        // When read, handle_read should kick in
        boost::asio::async_read_until(
            socket_,
            input_buffer_,
            '\n',
            boost::bind(
                &tcp_connection::handle_read,
                shared_from_this(),
                boost::asio::placeholders::error
            )
        );
    }

    // When stream is received, handle the message from the client
    void handle_read(const boost::system::error_code& ec) {

        std::cout << "HANDLE_READ - line 101" << "\n";
        messageFromClient_ = "";
        if (!ec) {
            // Extract the newline-delimited message from the buffer.
            std::string line;
            std::istream is(&input_buffer_);
            std::getline(is, line);

            // Empty messages are heartbeats and so ignored.
            if (!line.empty()) {
                messageFromClient_ += line;
                std::cout << "Received: " << line << "\n";
            }
            start_read();
        }
        else {
            std::cout << "Error on receive: " << ec.message() << "\n";
        }
    }

    // handle_write() is responsible for any further actions
    // for this client connection.
    void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) {
        m_message += "helloo\n";
    }

    tcp::socket socket_;
    std::string m_message;
    boost::asio::streambuf input_buffer_;
    std::string messageFromClient_;
};

class tcp_server {
    public:
        // Constructor: initialises an acceptor to listen on TCP port 14002.
        tcp_server(boost::asio::io_service& io_service)
        : acceptor_(io_service, tcp::endpoint(tcp::v4(), 14002))
        {
            // start_accept() creates a socket and
            // initiates an asynchronous accept operation
            // to wait for a new connection.
            start_accept();
        }

private:
    void start_accept() {
        // creates a socket
        cout << "creating a new socket for the communication" <<endl;
        tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service());

        // initiates an asynchronous accept operation
        // to wait for a new connection.
        acceptor_.async_accept(
            new_connection->socket(),
            boost::bind(
                &tcp_server::handle_accept,
                this,
                new_connection,
                boost::asio::placeholders::error
            )
        );
    }

    // handle_accept() is called when the asynchronous accept operation
    // initiated by start_accept() finishes. It services the client request
    void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) {

        if (!error) {
            cout << "Starting the new tcp connection" <<endl;
            new_connection->start();
        }

        // Call start_accept() to initiate the next accept operation.
        start_accept();
    }

    tcp::acceptor acceptor_;
};


int inline launch_server() {
    try {
        boost::asio::io_service io_service;
        tcp_server server(io_service);

        // Run the io_service object to perform asynchronous operations.
        io_service.run();
    }
    catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

Sending the message from the C++ to NodeJS works (the async_write(..) in the start() while loop, which sends _coordinates every 1ms), but I can't manage to handle the messages coming from my NodeJS program : 将消息从C ++发送到NodeJS工作( start() while循环中的async_write(..) ,每隔1ms发送_coordinates ),但我无法处理来自我的NodeJS程序的消息

When running (both programs on my computer, on localhost), the output of ss -tp | grep 14002 运行时(我的计算机上的两个程序,在localhost上), ss -tp | grep 14002的输出 ss -tp | grep 14002 (14002 being the port), the Recv-Q/Send-Q of the NodeJS process are empty (and the socket.write(...) returns successful), while, for the C++ part, the Recv-Q is constantly growing and Send-Q is empty Moreover, when running, all the cout .. of the handler_read() are not printed, which means that the async_read_until() function never calls the handler. ss -tp | grep 14002 (14002是端口),NodeJS进程的Recv-Q / Send-Q是空的(并且socket.write(...)返回成功),而对于C ++部分,Recv-Q是不断增长并且Send-Q为空此外,在运行时,不会打印handler_read()所有cout ..这意味着async_read_until()函数永远不会调用处理程序。

I tried all the overload versions of the async_read_until() , none of them works. 我尝试了async_read_until()所有重载版本,它们都async_read_until() And, as the messages are not of constant size, it seems that i have no choice but to use read_until. 而且,由于消息的大小不一致,似乎我别无选择,只能使用read_until。

I hope I didn't forget any useful information. 我希望我没有忘记任何有用的信息。 Thank you for your help ! 谢谢您的帮助 !

You are basically saturating your CPU with the infinite while loop in your tcp_connection::start method. 你基本上在tcp_connection::start方法中使用无限循环来使你的CPU饱和。 Not only that it is saturating the CPU, it is also a bug in your design. 它不仅会使CPU饱和,而且还会影响您的设计。 Why would you want to continuously attach handlers for read and also send/write data to the socket in a infinite loop ? 为什么要连续附加处理程序以进行读取,以及在无限循环中将数据发送/写入套接字? Most probably you want to write to the socket after receiving a request from the client. 很可能您希望在收到客户端的请求后write套接字。

Below are the methods I changed to make it work like a regular client-server: 以下是我更改的方法,使其像常规客户端服务器一样工作:

void start() {
          start_read();

          // This is going to read after every 1ms the _coordinates variable
          usleep(1000);
          m_message = _coordinates;
        }

void start_read() {
        // Start an asynchronous operation to read a newline-delimited message.
        // When read, handle_read should kick in
        boost::asio::async_read_until(
            socket_,
            input_buffer_,
            '\n',
            boost::bind(
                &tcp_connection::handle_read,
                shared_from_this(),
                boost::asio::placeholders::error
            )
        );
    }

void handle_read(const boost::system::error_code& ec) {

        std::cout << "HANDLE_READ - line 101" << "\n";
        messageFromClient_ = "";
        if (!ec) {
            // Extract the newline-delimited message from the buffer.
            std::string line;
            std::istream is(&input_buffer_);
            std::getline(is, line);

            // Empty messages are heartbeats and so ignored.
            if (!line.empty()) {
                messageFromClient_ += line;
                std::cout << "Received: " << line << "\n";
            }
            start_read();
        }
        else {
            std::cout << "Error on receive: " << ec.message() << "\n";
        }

        start_read();

        boost::asio::async_write(
                    socket_,
                    boost::asio::buffer(m_message),
                    boost::bind(
                        &tcp_connection::handle_write,
                        shared_from_this(),
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred
                    )
                );
    }

I am not sure what you are 'actually' trying to do based on the question as it stands now, but the above changes should be a good point to start with. 我不确定你实际上是根据现在的问题尝试做什么,但上述变化应该是一个很好的开始。

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

相关问题 Boost :: asio async_read简单文件上传 - Boost::asio async_read simple file upload AngularJS $ http服务永远不会调用错误处理程序 - AngularJS $http service never calls the error handler JavaScript 等待所有异步调用完成 - JavaScript Wait until all async calls finish jQuery等到async ajax调用完成 - jQuery Wait until async ajax calls are finished 在chrome中阻止webRequest处理程序中使用异步调用 - Use async calls in a blocking webRequest handler in chrome VanillaJS vs JQuery-等待处理程序,直到完成两个异步请求 - VanillaJS vs JQuery - wait handler until two async requests are done boost::asio 是否支持 websockets? - Does boost::asio support websockets? 使用 RxJS 如何缓冲函数调用,直到其他异步函数调用已解决 - Using RxJS how to buffer function calls until an other async function call has resolved Angular fire 2异步调用一次,但在第一次完成之前不处理第二次回调 - Angular fire 2 async calls at once but do not process the second callback until the first finishes 停止执行代码,直到我的 async/await HttpClient get 操作完成执行代码(包括 html 调用) - Stop executing code until my async/await HttpClient get operation finishes executing code (including html calls)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM