简体   繁体   中英

Boost asio, shared_from_this() error R6010, and async_read() eof

I'm trying to make a chat with boost asio, having the officals example as reference. But i'm actually having two problems with async_read, first, why do I have an EoF(end of file) and my connexion(and application) close so quickly in the client?

And then I have a problem in the async_read of ChatParticipant : if I pass "Shared_from_this()" as second argument of boost::bind I get and error R6010, but if i pass a simple "this", I don't have it.

Thanks for your help :)

Here is my concerned code :

Chat Server

    class ChatServer
    {
    public:
        ChatServer(boost::asio::io_service& io_service, const tcp::endpoint& endpoint): _io_service(io_service), _acceptor(io_service, endpoint)
        {
            startAccept();
        }

        void startAccept()
        {
            std::cout << "accepting a new client" << std::endl;
            shared_ptr<ServerParticipant> newParticipant(new ServerParticipant(_io_service, &_room));
            _acceptor.async_accept(newParticipant->getSocket(), boost::bind(&ChatServer::handleAccept, this, boost::asio::placeholders::error, newParticipant));
        }

        void handleAccept(const boost::system::error_code& e, shared_ptr<ServerParticipant> newParticipant)
        {
            if (!e)
            {

                std::cout << "accepted a new client" << std::endl;
                boost::asio::async_read(newParticipant->getSocket(),
                    boost::asio::buffer(_readMsgCache.getAllMessage(), ChatMessage::header_length),
                    boost::bind(&ChatServer::read, this,
                boost::asio::placeholders::error));
                //newParticipant->start();
                startAccept();
            }
            else
            {
                std::cerr << e.message() << std::endl;
            }
        }

        void read(const boost::system::error_code& e)
        {
            if (e && e == boost::asio::error::eof)
            {
                std::cerr << "closed" << std::endl;
            }
            if (e)
            {
                std::cerr << e.message() << std::endl;
            }

            else
            {
                std::cout << "Reaaad" << std::endl;
            }

        }
    private:
        boost::asio::io_service& _io_service;
        tcp::acceptor _acceptor;
        ChatMessage _readMsgCache;
}

Chat Participant

    class ChatParticipant : public boost::enable_shared_from_this<ChatParticipant>
    {
    public :
        ChatParticipant(boost::asio::io_service& service) : _id(0), _service(service), _socket(service)
        {}

        virtual void start()
        {
            startRead();
        }

        void startRead()
        {
            std::cout << "Start read" << std::endl;
            boost::asio::async_read(_socket,
                boost::asio::buffer(_readMsgCache.getAllMessage(), 4),
            boost::bind(
            &ChatParticipant::readHeader, shared_from_this(),
              boost::asio::placeholders::error));
        }
// some functions about decoding the message...

protected:
    int _id;
    boost::asio::io_service& _service;
    tcp::socket _socket;


    std::deque<ChatMessage> _writeMsgCache;
    ChatMessage _readMsgCache;

Chat Client

using boost::asio::ip::tcp;

class ChatClient
{
public:
    ChatClient(boost::asio::io_service& service, tcp::endpoint& endpoint) : _service(service), _client(service)
    {
        _client.getSocket().async_connect(endpoint, boost::bind(&ChatClient::handleConnect, this, boost::asio::placeholders::error));
    }


    void handleConnect(const boost::system::error_code& err)
    {

        if (err)
        {
            std::cerr << err.message();
        }
        else
        {
            _client.start();

            /*
            ChatMessage message;
            message.setMessage("hello");
            _client.speak(message);
            */
        }
    }

    void read(const boost::system::error_code& e)
    {
        if (e)
        {
            std::cerr << e.message() << std::endl;
        }
        else
        {
            std::cout << "Reaaad" << std::endl;
        }

    }
protected :
    boost::asio::io_service& _service;
    ChatParticipant _client;
};

ChatMessage

#pragma once
#include <stdlib.h>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>

using namespace std;
class ChatMessage
{
public :
    enum{header_length = 4};
    static const size_t headerLength = 4; 
    static const size_t maxMsgLength = 512;

    ChatMessage()
    {
        clear();
    }

    void clear()
    {
        for (size_t i = 0; i <= maxLength() ; ++i)
            _allMessage[i] = '\0';
    }

    char* getAllMessage()
    {
        return _allMessage;
    }

    const char* getAllMessage() const
    {
        return _allMessage;
    }

    char* getBody()
    {
        return _allMessage + headerLength;
    }

    size_t getBodyLength()
    {
        return _bodyLength;
    }

    size_t length()
    {
        return headerLength + _bodyLength;
    }

    const size_t length() const
    {
        return headerLength + _bodyLength;
    }

    size_t maxLength()
    {
        return headerLength + maxMsgLength;
    }

    bool setBody(const char* message)
    {
        _bodyLength = strlen(message);
        if (_bodyLength > maxMsgLength)
            return false;
        memcpy(getBody(), message, _bodyLength);
        return true;
    }

    bool setMessage(const char* message)
    {
        clear();
        if (!setBody(message))
            return false;
        encodeHeader();
        return true;
    }
    #pragma warning(disable: 4996) /* Disable deprecation */
    bool decodeHeader()
    {
        char header[headerLength + 1] = "";
        strncat(header, _allMessage, headerLength);
        _bodyLength = atoi(header);
        if (_bodyLength > maxMsgLength)
            return false;
        return true;
    }

    void encodeHeader()
    {
        stringstream ss;
        ss << setw(headerLength) << _bodyLength;
        string s(ss.str());
        memcpy(_allMessage,s.c_str(), headerLength);

    }

private :
    char _allMessage[headerLength + maxMsgLength];
    size_t _bodyLength;
};

main

#include "ChatMessage.h"


#define IsServer true
#ifdef IsServer
    #include "ChatServer.h"
#else
    #include "ChatCLient.h"
#endif

using boost::asio::ip::tcp;
int main()
{
    boost::asio::io_service service;

    #ifdef IsServer
        tcp::endpoint endpoint(tcp::v4(), 13);
        std::cout << "Server start" << std::endl;
        ChatServer server(service, endpoint);
    #else
        tcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("127.0.0.1"), 13);
        std::cout << "Client start" << std::endl;
        ChatClient client(service, endpoint);
    #endif

    service.run();
    return 0;
}

The R6010 error is probably caused by an uncaught exception. shared_from_this() is based on a weak pointer and its operation depends upon the object being the target of a shared pointer.

That is:

 shared_ptr<ChatClient> client1 (new ChatClient);
 // this client can use shared_from_this()

but

ChatClient client2;
// this client cannot use shared_from_this().

change

ChatParticipant _client;

to

boost::shared_ptr<ChatParticipant> _client;

and initialize the _client pointer in the ctor initialization list. This will allow you to invoke shared_from_this() to get a shared_ptr to _client .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM