0

为了实现 type 的习惯用法SOCKET,我创建了一个包装器。包装器connect在构造函数closesocket及其析构函数中调用。Astd::map持有所有使用过的套接字。不幸的是,将一个新套接字插入容器会调用临时的析构函数,实际上是关闭刚刚打开的套接字。有没有一种通用的方法来克服这个问题?

这是代码:

#include <iostream>
#include <stdexcept>
#include <map>
#include <winsock2.h>

struct Socket {
    SOCKET mSock;
    Socket() : mSock(INVALID_SOCKET) {}
    Socket(std::string ip, int port);
    ~Socket();
};

Socket::Socket(std::string ip, int port) {
    mSock = socket(AF_INET, SOCK_STREAM, 0);
    if (mSock == INVALID_SOCKET)
        throw std::runtime_error("socket()");
    SOCKADDR_IN addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    if (connect(mSock, reinterpret_cast<SOCKADDR*>(&addr), sizeof(addr))
        == SOCKET_ERROR)
        throw std::runtime_error("connect()");
    std::cout << mSock << " connected" << std::endl;
}

Socket::~Socket() {
    if (mSock != INVALID_SOCKET) {
        closesocket(mSock);
        std::cout << mSock << " closed" << std::endl;
    }
}

int main() {
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 0), &wsa);
    std::map<int, Socket> outbound;
    // calls constructur but also destructor
    outbound[0] = Socket("192.168.128.125", 4023);
    WSACleanup();
    return 0;
}

输出是:

1952 connected
1952 closed
1952 closed
4

2 回答 2

4

如果您将资源保护器包装在智能指针中,则它们可以存储在 STL 容器中。究竟使用哪个智能指针取决于您的环境,如果您不确定,我建议您以 boost::shared_ptr 作为起点。

按照这种方式,您将符合资源保护语义(只有一个管理资源生命周期的实例)和 STL 容器(保留传递项目的等效副本)。

于 2013-07-25T17:11:34.253 回答
1

正如其他人所提到的,您应该防止复制 Socket 对象,这可以通过添加来完成:

private:
  Socket(const Socket &){}
  Socket & operator=(const Socket &){return *this;}

然后要实际连接,您可以在默认构造之后使用连接方法的实现来执行此操作,该方法可以显式调用,也可以由剩余的构造函数调用:

bool Socket::connect(std::string ip, int port) {
    mSock = socket(AF_INET, SOCK_STREAM, 0);
    if (mSock == INVALID_SOCKET)
        return false;
    SOCKADDR_IN addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(ip.c_str());
    if (connect(mSock, reinterpret_cast<SOCKADDR*>(&addr), sizeof(addr))
        == SOCKET_ERROR)
        return false;
    std::cout << mSock << " connected" << std::endl;
    return true;
}

Socket::Socket(std::string ip, int port) {
    if (!connect(ip, port))
        throw std::runtime_error("socket()");
}
于 2013-07-25T18:52:06.657 回答