Search code examples
c++boosttcpboost-asiotcpclient

Boost ASIO Tcp Client/Server object connect issue


I'm trying to make an "connection handler" for Client and server the server-side works quite well with an other client but when i try to connect a client made the object, i've always the same crash and it appears right after the socket->connect.

this is the error from the client:

terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
  what():  bind: Address already in use

this is my TCP.cpp:

TCP::TCP(TYPE type)
{
    switch (type)
    {
        case (CLIENT):
            setup_client();
        case (SERVER):
            setup_server();
        default:
            break;
    }
}

TCP::~TCP()
{
    _socket->close();
}

void TCP::setup_client()
{
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"), PORT);
    _socket = new tcp::socket(_io_service);
    _socket->connect(endpoint);
}

void TCP::setup_server()
{
    _acceptor = new tcp::acceptor(_io_service, tcp::endpoint(tcp::v4(), PORT ));  //listen for new connection
    _socket = new tcp::socket(_io_service);  //socket creation 
    _acceptor->accept(*_socket);  //waiting for connection
}

string TCP::read_socket() {
    boost::asio::streambuf buf;
    boost::asio::read_until(*_socket, buf, "\n" );
    string data = boost::asio::buffer_cast<const char*>(buf.data());
    return data;
}

void TCP::send_socket(const string& message)
{
    const string msg = message + "\n";
    boost::asio::write(*_socket, boost::asio::buffer(message) );
}

and this my .hpp:

#define PORT 8080

enum TYPE {
    CLIENT,
    SERVER
};

class TCP {
    public:
        TCP(TYPE type);
        ~TCP();
        string read_socket();
        void send_socket(const string& message);

    protected:
    private:
        void setup_server();
        void setup_client();

        boost::asio::io_service _io_service;
        tcp::acceptor *_acceptor;
        tcp::socket *_socket;
};

Solution

  • You're missing a break statement:

    TCP::TCP(TYPE type) {
        switch (type) {
        case (CLIENT):
            setup_client();
            break;
        case (SERVER):
            setup_server();
            break;
        default:
            break;
        }
    }
    

    This means that your client also tries to open an acceptor on the same port. That is normally not allowed.

    Simplified

    Removing a lot of bug sources:

    Live On Coliru

    #define PORT 8383
    #include <boost/asio.hpp>
    #include <iostream>
    using namespace std::chrono_literals;
    using boost::asio::ip::tcp;
    using boost::system::error_code;
    
    struct TCP {
        enum TYPE { CLIENT, SERVER };
    
        TCP(TYPE type);
        ~TCP();
        std::string read_socket();
        void send_socket(const std::string& message);
    
      private:
        boost::asio::io_service _io_service;
        tcp::socket _socket { _io_service };
        tcp::acceptor _acceptor { _io_service };
    };
    
    TCP::TCP(TYPE type) {
        if (type == CLIENT) {
            _socket.connect(tcp::endpoint{ {}, PORT});
        } else {
            _acceptor = tcp::acceptor{_io_service, {{}, PORT}};
            //_acceptor.bind({{}, PORT});
            _acceptor.accept(_socket);
        }
    }
    
    TCP::~TCP() {
        if (_socket.is_open())   _socket.close();
        if (_acceptor.is_open()) _acceptor.close();
    }
    
    std::string TCP::read_socket() {
        std::string data;
        auto n = read_until(_socket, boost::asio::dynamic_buffer(data), "\n");
        data.resize(n);
        return data;
    }
    
    void TCP::send_socket(const std::string& message) {
        write(_socket, boost::asio::buffer(message + "\n"));
    }
    
    int main() {
        std::thread server_th([&] {
            TCP s(TCP::SERVER);
            s.send_socket("ECHO: " + s.read_socket());
        });
    
        std::thread client_th([&] {
            std::this_thread::sleep_for(10ms);
            TCP c(TCP::CLIENT);
            c.send_socket("Hello world!");
            std::cout << c.read_socket() << "\n";
        });
    
        client_th.join();
        server_th.join();
    }
    

    Prints

    ECHO: Hello world!