无法在 asio 中将 keep_alive 设置为套接字

Can't set keep_alive to socket in asio

我正在尝试将 ServerSocket 创建为单例。这是代码:

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;
}

问题是在 InitSocket 中,当 运行 调试器时,似乎 set_option 由于某种原因不起作用,然后抛出异常 - 我无法理解为什么。

抛出的异常是:set_option: 提供的文件句柄无效。

如何在我的套接字中将 keep_alive 选项设置为 true?这种方式好像不行。

@Vasile,正如@dewaffed 告诉您的那样,您的问题是您在打开套接字之前设置选项。

我不知道您要做什么,但我可以看到您创建了一个未打开的新套接字并设置了属性,这就是问题所在。正确的方法是:

  1. 创建套接字
  2. 使用您之前创建的套接字接受新连接。
  3. 一旦接受器结束接受新连接,套接字就会有一个有效的文件描述符,这是在套接字上设置选项所必需的。

检查这些链接:

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

,其中谈到了你的异常。

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