【问题标题】:boost tcp socket with shared_ptr c++使用 shared_ptr c++ 提升 tcp 套接字
【发布时间】:2013-02-28 02:12:18
【问题描述】:

我正在尝试使用 c++ 中的一个新类来包装 boost TCP。当我直接调用 boost 函数时,事情就像一个魅力。但是,当关闭包装在类函数中时,我无法调用套接字关闭。请帮忙看看下面的代码。

类定义:

typedef boost::shared_ptr<tcp::socket> Socket;
class TCPConnector{
public :
    bool isConnected;
    Socket sock;
    string ip;
    int port;
    TCPConnector(string ip, int port);

    void Close();
    bool Connect();
};

功能:

TCPConnector::TCPConnector(string ip,int port):ip(ip),port(port)
{

}

void TCPConnector::Close() {
    boost::system::error_code error;
    if (!isConnected)
        return;
    isConnected = false;

    try {

        sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both, error);
        cout << "ShutDown" << endl;
        if (error)
            throw boost::system::system_error(error);
        sock->close(error);
        if (error)
            throw boost::system::system_error(error);
    } catch (exception& e) {
        cout << "#TCPConnector::Close()#" << e.what() << endl;
    }
}

主要功能:

int main(int argc, char* argv[]) {
    try {
        TCPConnector* conn = new TCPConnector("127.0.0.1",8088);

        for (int i = 0; i < 2; i++) {
            boost::asio::io_service io_service;
            tcp::resolver resolver(io_service);
            tcp::resolver::query query(tcp::v4(), "127.0.0.1", "8088");
            tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
            conn->sock.reset(new tcp::socket(io_service));
            conn->sock->connect(*endpoint_iterator);
            cout << "Connected" << endl;
            boost::thread acceptorThread(boost::bind(receive,conn));
            sleep(1);
            unsigned char msg[8] = { 0, 6, 55, 56, 55, 56, 55, 0 };
            boost::system::error_code error;
            try {

                boost::asio::write(*conn->sock, boost::asio::buffer(msg, 8),
                        boost::asio::transfer_all(), error);
                cout << "Sent" << endl;
                if (error)
                    throw boost::system::system_error(error);
                conn->sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both,
                        error);
                if (error)
                    throw boost::system::system_error(error);




                conn->sock->close(error);//close socket directly , the result is ok
                //conn->Close();// close by calling functions, it causes problems.





                cout << "Closed" << endl;
                if (error)
                    throw boost::system::system_error(error);
                io_service.stop();
            } catch (std::exception& e) {
                std::cerr << "Exception in thread: " << e.what() << "\n";
            }
            cout << "Sleep" << endl;
            sleep(2);
            cout << "Wake up" << endl;
        }
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

这两行给出了不同的行为。我不知道为什么第二个会导致问题。

conn->sock->close(error);//close socket directly , the result is ok
conn->Close();// close by calling functions, it causes problems.

mutex: Invalid argument 打印在

sock->close(error);
        if (error)
            throw boost::system::system_error(error);

问题与shared_ptr有关吗?还是我错过了关闭套接字的重要内容?

感谢您的任何建议。

【问题讨论】:

  • io_service 应该比socket 寿命更长。尝试将 io_service 移到 for 循环之外,或在 for 循环结束时调用 conn-&gt;sock.reset();
  • 感谢您的回复。在第一个循环中,在 conn-&gt;Close(); 之后抛出错误,因此程序无法继续。或者你的意思是在conn-&gt;Close();之前调用conn-&gt;sock.reset()
  • @Fraser 非常感谢!在conn-&gt;Close(); 之前添加conn-&gt;sock.reset(); 后,代码现在可以工作了。我可以试着解释一下,你帮助评估它是否正确。由于conn-&gt;sock.reset(new tcp::socket(io_service));io_service.stop(); 之后运行,因此io_service 的寿命比套接字长(在前循环中关闭)。但是为什么这会导致互斥错误以及为什么io_service 必须比套接字寿命更长?真的非常感谢!
  • @Fraser 还有一个问题,shared_ptr的reset函数会运行socket的析构函数吗?如果是,为什么调用 reset 后可以使用 sock?谢谢
  • 并非总是如此,reset 等同于 swap。仅当调用时use_count 为 1 时,它才会运行托管对象的析构函数。在这种情况下(因为use_count is 1)它确实运行了套接字的析构函数。如果在循环结束时调用reset()(相当于将ptr 设置为nullptr),则在io_service 仍然有效时运行套接字的析构函数。如果你不这样做,循环开始附近的 reset 在分配新值之前执行前一个迭代的套接字的析构函数 - 到那时前一个迭代的 io_service 无效。

标签: c++ boost tcp boost-asio shared-ptr


【解决方案1】:

问题是io_service 应该比socket 寿命更长。

除了for 循环的第一次迭代之外,语句conn-&gt;sock.reset(new tcp::socket(io_service)); 调用前一次迭代的套接字的析构函数。这个析构函数访问之前迭代的io_service(特别是它的互斥体)的元素,这些元素本身已经被销毁了。

要解决此问题,您可以将io_service 移到for 循环之外,或者您可以在for 循环结束时调用conn-&gt;sock.reset(); 以调用socket 的析构函数,而io_service 仍然有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 2018-04-03
    相关资源
    最近更新 更多