2

c++ で新しいクラスを使用してブースト TCP をラップしようとしています。ブースト機能を直接呼び出している間、物事は魅力のように機能します。ただし、クローズがクラス関数でラップされている間、ソケットのクローズを呼び出すことができません。次のコードをご覧ください。

クラス定義:

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

これらの 2 行は、異なる動作を提供します。2番目のものが問題を引き起こす理由がわかりません。

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

ミューテックス: 無効な引数が出力されました

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

問題は shared_ptr に関連していますか? または、ソケットを閉じるために重要なことを見逃しましたか?

提案をありがとう。

4

1 に答える 1

3

問題は、io_serviceが よりも長生きする必要があることsocketです。

forループの最初の反復を除くすべての反復で、ステートメントconn->sock.reset(new tcp::socket(io_service));は前の反復のソケットのデストラクタを呼び出します。このデストラクタは、その時点までにそれ自体が破棄された、前の繰り返しの要素io_service(具体的にはそのミューテックス) にアクセスします。

これを修正するには、 をループの外側に移動するかio_service、ループの最後でを呼び出して、がまだ有効な間に のデストラクタを呼び出すことができます。forconn->sock.reset();forsocketio_service

于 2013-02-28T09:06:48.190 に答える