Asio tcp套接字上未初始化的读取错误

时间:2014-07-08 13:52:18

标签: c++ sockets boost tcp boost-asio

我有一个c ++ windows应用程序,工作正常。我使用Boost::asio。当我尝试在Linux上移植时,应用程序根本无法正常工作。在被valgrind错误沮丧之后,我决定在Windows上运行DrMemory并修复首先出现的错误。我无法解决的一个错误是我已经扣除了关于我的套接字的错误。是否无法将scoped_ptr与套接字一起使用?无论如何,这里是DrMemory记录的错误,后面是一些相关的代码。如果我将套接字的逻辑从智能指针更改为引用或裸指针,则代码不会编译。 (关于套接字的一些错误,我无法回想起它是什么,但它对于引用和指针是相同的)

我做错了什么?

DrMemory:http://pastebin.com/gHQYrCjA

NetworkEntity.cpp

#include "boost/asio.hpp"
#include "NetworkEntity.h"
#include "boost/bind.hpp"

NetworkEntity::NetworkEntity(std::string address, std::string port)
  : address_(address), 
    port_(port)
{
}

void NetworkEntity::stop()
{
    if (socket_)
    {
        socket_->close();
    }
    socket_.reset();
    timeout_->cancel();
}

void NetworkEntity::check_timeout(const boost::system::error_code& error)
{
    if (error != boost::asio::error::operation_aborted)
    {
        stop();

        errorbuf_  << "timed out after " << TIMEOUT_ << " seconds\n";

    }
}

std::vector<std::string> NetworkEntity::tcpPoll(const char* message, const char endOfMessage)
{
    boost::asio::io_service io_service;
    try{
        //initialize timeout timer.
        timeout_.reset(new boost::asio::deadline_timer(io_service));
        timeout_->expires_from_now(boost::posix_time::seconds(TIMEOUT_));
        timeout_->async_wait(boost::bind(&NetworkEntity::check_timeout, this, boost::asio::placeholders::error));
        //initialize connection, which writes then reads.
        tcp::resolver resolver(io_service);
        start_connect(&io_service, resolver.resolve(tcp::resolver::query(address_, port_)), message, endOfMessage);
        //run async operations, wait for their completion.
        io_service.run();

        //retrieve answer
        std::vector<std::string> lines;
        std::string line;
        std::istream is(&answer_);
        int i = 0;
        while (std::getline(is, line)){ 
            lines.push_back(line); 
        }
        //reset answer to nothing (not needed but is a security)
        answer_.consume(answer_.size());
        request_.consume(request_.size());
        setError(errorbuf_.str());
        errorbuf_.str(""); // clear the contents
        errorbuf_.clear();
        return lines;
    }
    catch (std::exception& e){

        errorbuf_ << "An exception has occured : " << e.what() << "\n";

        return std::vector<std::string>{};
    }
}

void NetworkEntity::start_connect(boost::asio::io_service* io_service, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endOfMessage)
{
    // Start the asynchronous connect operation.
    socket_.reset(new tcp::socket(*io_service));
    socket_->async_connect(endpoint_iterator->endpoint(),
        boost::bind(&NetworkEntity::handle_connect, this, io_service, boost::asio::placeholders::error, message, endOfMessage));
}

void NetworkEntity::handle_connect(boost::asio::io_service* io_service, const boost::system::error_code& err, const std::string message, const char endOfMessage)
{
    if (err)
    {
        stop();

        errorbuf_ << "Connect error : " << err.message() << "\n";

    }
    else
    {
        start_write(message, endOfMessage);
    }
}

void NetworkEntity::start_write(const std::string message, const char endOfMessage)
{
    //convert message from string to streambuf
    std::ostream request_stream(&request_);
    request_stream << message;
    //end of convertion
    boost::asio::async_write(*socket_, request_,
        boost::bind(&NetworkEntity::handle_write, this, boost::asio::placeholders::error, endOfMessage));
}

void NetworkEntity::handle_write(const boost::system::error_code& error, const char endOfMessage)
{
    if (!error)
    {
        boost::asio::io_service io;
        boost::asio::deadline_timer wait(io);
        wait.expires_from_now(boost::posix_time::milliseconds(500));
        wait.wait();
        start_read(endOfMessage);
    }
    else
    {
        stop();

        errorbuf_ << "Write error : " << error.message() << "\n";

    }
}

void NetworkEntity::start_read(const char endOfMessage)
{
    boost::asio::async_read_until(*socket_, answer_, endOfMessage,
        boost::bind(&NetworkEntity::handle_read, this, boost::asio::placeholders::error));
}

void NetworkEntity::handle_read(const boost::system::error_code& error)
{
    if (error)
    {

        errorbuf_ << "read error : " << error.message() << "\n";

    }
    stop();
}

NetworkEntity.h

#inclued "boost/asio.hpp"
#include "boost/array.hpp"
#include "boost/scoped_ptr.hpp"
#include "boost/shared_ptr.hpp"
#include "Error.h"

#ifndef NETWORK_ENTITY_H
#define NETWORK_ENTITY_H

using boost::asio::ip::tcp;
class NetworkEntity : private boost::noncopyable
{
public:
    NetworkEntity(std::string address, std::string port);

    std::vector<std::string> tcpPoll(const char* message, const char endOfMessage);

private:
    void stop();
    void check_timeout(const boost::system::error_code&  error);
    void start_write(const std::string message, const char endOfMessage);
    void handle_write(const boost::system::error_code& error, const char endOfMessage);
    void start_read(const char endOfMessage);
    void start_connect(boost::asio::io_service* io_service, tcp::resolver::iterator endpoint_iterator, const std::string message, const char endOfMessage);
    void handle_connect(boost::asio::io_service* io_service, const boost::system::error_code& error, const std::string message, const char endOfMessage);
    void handle_read(const boost::system::error_code& error);
    void timeoutHandler(const boost::system::error_code& error);
    boost::scoped_ptr<tcp::socket> socket_;
    boost::scoped_ptr<boost::asio::deadline_timer> timeout_;
    std::string address_;
    std::string port_;
    boost::asio::streambuf answer_;
    boost::asio::streambuf request_;
    static const int TIMEOUT_ = 5;

    std::stringstream errorbuf_; //loggable by functions I removed for the sake of simplicity
    boost::shared_ptr<Error> error_;
    boost::scoped_ptr<boost::asio::deadline_timer> logTimer_;

    NetworkEntity(const NetworkEntity& e) = delete;
    NetworkEntity & operator=(const NetworkEntity& e) = delete;
};
#endif

main.cpp(我没有尝试编译这个,对不起,如果有任何错误)

#include "NetworkEntity.h"
#include <iostream>

    int main()
{
    NetworkEntity n("192.168.0.36", "10001");
    while (true){
        std::string mes;
        std::cin >> mes;
        std::vector<std::string> ans = n.tcpPoll(mes.c_str(), '\n'); //message to send, last character expected to recieve (read until)
        for (int i = 0; i < ans.size(); i++)
            std::cout << ans[i] << "\n";
    }
}

3 个答案:

答案 0 :(得分:1)

希望能帮助您找到问题的一些提示:

  1. boost::asio::io_service io_serviceNetworkEntity::tcpPoll移至类成员变量。
  2. 我不会遗忘您为什么在NetworkEntity::handle_write中创建另一个ioservice,使用成员变量。
  3. NetworkEntity::tcpPoll中,“timeout_.reset(new boost::asio::deadline_timer(io_service))”会造成内存泄漏,请使用std::make_shared
  4. 当你'重置'套接字时,我不理解NetworkEntity::handle_write中的错误处理,并继续NetworkEntity::tcpPoll中的io_service.run(),甚至没有出现错误。
  5. 最后但并非最不重要的是,关于你的问题'是否不可能将scoped_ptr与套接字一起使用?',套接字是一回事,指针,作用域或不是另一回事。您应该阅读并了解智能指针,该术语背后没有任何魔法,只有引用计数,当该计数达到0时删除。

    作为免费建议的奖励:忘记DrMemory并准确理解每一行,代码的每个陈述,如果函数有返回值,得到它并检查它......

    祝你好运!

答案 1 :(得分:0)

socket_.reset();

应位于先前的'if'区块内。

答案 2 :(得分:0)

最后,我让它在linux上运行并运行valgrind-clean。我的问题甚至不在这里显示的内容,而是我正在传递"10001\r"而不是"10001"作为端口,这使得解析器失败。 \r getline来自\n(从文件中读取),仅删除了"10001\r\n"中的{{1}}