boost :: asio, ошибка асинхронного чтения - PullRequest
7 голосов
/ 03 августа 2009

По какой-то причине это приводит к нарушению доступа, однако не имея подробной документации / справки по этому вопросу, я не уверен, где я делаю это неправильно. Начиная с того, что я видел на буст-сайте, это должно быть правильно, и печатать содержимое каждого вызова asio :: write от клиента в новую строку. Клиент, кажется, работает нормально. Хотя в тот момент, когда сервер дает сбой, он еще ничего не отправил.

Нарушение доступа происходит в basic_stream_socket.hpp в строке 275. Кажется, причина в том, что объект (boost :: asio :: stream_socket_service) не инициализирован (значение этого указателя 0xfeeefeee), однако не понимаю, почему это не так.

Вывод программ:

Запустить сервер
Server :: startAccept ()
Server :: handleAccept ()
Соединение принято
Подключение :: startRead ()
Server :: startAccept ()
Подключение :: handleRead ()
READ ERROR: операция ввода-вывода была прервана из-за выхода из потока или запроса приложения
Connection :: startRead ()

код

#include "precompiled.h"
#include "db.h"
class Connection
    : public boost::enable_shared_from_this<Connection>
{
public:
    typedef boost::shared_ptr<Connection> Pointer;

    static Pointer create(boost::asio::io_service& ioService)
    {
        return Pointer(new Connection(ioService));
    }

    ip::tcp::socket& getSocket()
    {
        return socket;
    }

    void startRead()
    {
        std::cout << "Connection::startRead()" << std::endl;
        socket.async_read_some(boost::asio::buffer(readBuffer),
            boost::bind(&Connection::handleRead,this,_1,_2));
    }
private:
    Connection(asio::io_service& ioService)
        : socket(ioService)
    {
    }

    void handleWrite(const boost::system::error_code&,size_t)
    {
    }
    void handleRead(const boost::system::error_code&error,size_t len)
    {
        std::cout << "Connection::handleRead()" << std::endl;
        if(error)
        {
            std::cout << "READ ERROR: ";
            std::cout << boost::system::system_error(error).what();
            std::cout << std::endl;
        }
        else
        {
            std::cout << "read: ";
            std::cout.write(readBuffer.data(),len);
            std::cout << std::endl;
        }
        startRead();
    }
    boost::array<char, 256> readBuffer;
    ip::tcp::socket socket;
};

class Server
{
public:
    Server(asio::io_service& ioService)
        :acceptor(ioService, ip::tcp::endpoint(ip::tcp::v4(), getPort()))
    {
        startAccept();
    }
private:
    void startAccept()
    {
        std::cout << "RServer::startAccept()" << std::endl;
        Connection::Pointer newConn =
            Connection::create(acceptor.io_service());

        acceptor.async_accept(newConn->getSocket(),
            boost::bind(&Server::handleAccept, this, newConn,
            asio::placeholders::error));
    }
    void handleAccept(Connection::Pointer newConn,
        const boost::system::error_code& error)
    {
        std::cout << "Server::handleAccept()" << std::endl;
        if(error)
        {
            std::cout << "CONNECTION ERROR: ";
            std::cout << boost::system::system_error(error).what();
            std::cout << std::endl;
        }
        else
        {
            std::cout << "Connection accepted" << std::endl;
            startAccept();
            newConn->startRead();
        }
    }
    ip::tcp::acceptor acceptor;
};

int main()
{
    std::cout << "Start server" << std::endl;
    asio::io_service ioService;
    RemoteAdminServer server(ioService);
    boost::system::error_code error;
    ioService.run(error);
}

Ответы [ 2 ]

11 голосов
/ 04 августа 2009

Вы должны изменить этот фрагмент кода:

   void startRead()
   {
       std::cout << "Connection::startRead()" << std::endl;
       socket.async_read_some(boost::asio::buffer(readBuffer),
                              boost::bind(&Connection::handleRead,this,_1,_2));
   }

до:

void startRead()
{
     std::cout << "Connection::startRead()" << std::endl;
     socket.async_read_some(boost::asio::buffer(readBuffer),
                boost::bind(&Connection::handleRead,this->shared_from_this(),_1,_2));
}

Обратите внимание, что я передал общий указатель в bind. Это будет поддерживать ваш экземпляр Connection до тех пор, пока не будет вызван обработчик. В противном случае счетчик использования обнуляется в Server::startAccept и объект удаляется. Затем, когда вызывается обработчик, память недействительна, и вы испытываете ужасное «неопределенное поведение».

0 голосов
/ 03 августа 2009

Я думаю, что ваш прогон существует, потому что у вас нет работы в рабочей очереди.

Вы не должны запускать и разрушать цикл вашего сервисного объекта.

Либо попробуйте это:

повышение :: ASIO :: io_service :: работа

или просто сделайте

do { ioService.run( error ); } while( !error );
...