1

I'm trying to create a ServerSocket as a singleton. Here's the code:

ServerSocket.h

#pragma once
#include <asio.hpp>
#include <iostream>
#include <optional>
 
using asio::ip::tcp;
 
class ServerSocket
{
public:
    ServerSocket(ServerSocket& otherSingleton) = delete;
    void operator= (const ServerSocket& copySingleton) = delete;
 
    tcp::acceptor* InitAcceptor();
    tcp::socket* InitSocket();
    void StartServerSocket();
    void SendData(std::string);
    std::optional<std::string> RecieveData();
 
    static ServerSocket* GetInstance();
 
private:
    static ServerSocket* instance;
 
    tcp::acceptor* acceptor;
    tcp::socket* socket;
    asio::io_context io_context;
 
    ServerSocket()
    {
        acceptor = InitAcceptor();
        socket = InitSocket();
    }
 
    ~ServerSocket() {
        delete socket;
        delete acceptor;
        std::cout << "Server closed";
    }
};

ServerSocket.cpp

#include "ServerSocket.h"
#include <optional>
 
tcp::acceptor* ServerSocket::InitAcceptor()
{
    try
    {
        return new tcp::acceptor(io_context, tcp::endpoint(tcp::v4(), 27015));
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return nullptr;
}
 
tcp::socket* ServerSocket::InitSocket()
{
    try
    {
        tcp::socket* deReturnat = new tcp::socket(io_context);
        asio::socket_base::keep_alive option(true);
        deReturnat->set_option(option);
        return deReturnat;
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return nullptr;
}
 
void ServerSocket::StartServerSocket()
{
    try
    {
        std::cout << "Server started";
        acceptor->accept(*socket);
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}
 
void ServerSocket::SendData(std::string)
{
}
 
std::optional<std::string> ServerSocket::RecieveData()
{
    try
    {
        char data[5000];
        asio::error_code error;
        size_t length = socket->read_some(asio::buffer(data), error);
        if (error == asio::error::eof) return std::nullopt; // Connection closed cleanly by peer.
            else if (error)
                throw asio::system_error(error); // Some other error.
         return std::string{ data, length };
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return {};
}
 
ServerSocket* ServerSocket::instance(nullptr);
 
ServerSocket* ServerSocket::GetInstance()
{
    if (instance == nullptr)
    {
        instance = new ServerSocket();
    }
    return instance;
}

The problem is that in InitSocket, when running a debugger, it seems like set_option doesn't work for some reason, and then an exception is thrown - and I can't understand why.

The exception that is thrown is: set_option: The file handle supplied is not valid.

How can I set the keep_alive option to true in my socket? It seems like this way doesn't work.

Vasile Mihai
  • 103
  • 6
  • 1
    Does this answer your question? [Modifying boost::asio::socket::set\_option](https://stackoverflow.com/questions/35154547/modifying-boostasiosocketset-option): `Before you set_option or get_option from a socket you must open it. ` In your case, you can set socket option immediately after the acceptor accepts connection. – dewaffled Dec 15 '21 at 23:00
  • unfortunately no as i'm trying to do a synchronous server, i tried putting the option exactly after the accept->socket part, and i had no success – Vasile Mihai Dec 15 '21 at 23:07

1 Answers1

1

@Vasile, your problem, as @dewaffed told you, is that you are setting the options before the socket has been opened.

I don't know what you are trying to do but I can see that you creating a new socket, which is not open, and setting the properties, that's the problem. The correct way is:

  1. Create the Socket
  2. Accept the new connection, with the previous socket you've created.
  3. Once the acceptor has ended to accept a new connection, the socket has a valid File Descriptor, which is required to set the option over the socket.

Check these links:

https://en.wikipedia.org/wiki/Berkeley_sockets

Modifying boost::asio::socket::set_option, which talks about your exception.

https://www.boost.org/doc/libs/1_77_0/doc/html/boost_asio/tutorial/tutdaytime2.html

Jorge Omar Medra
  • 978
  • 1
  • 9
  • 19