在一个进程中,能否判断WSAStartup是否已经被调用?

19

我已经开始编写一个利用 sockets 的 ActiveX 控件。

使用此控件的应用程序可能会或可能不会同时使用 sockets。 我的控件是否能够判断 WSAStartup 是否已经被调用?

如果不能,就调用它。通过一个简单的测试可以发现,多次调用 WSAStartup 是被允许的。 但是,如果请求不同的 winsock 版本,会不会破坏应用程序的其他部分呢?

2个回答

32

是的,这是可能的。

下面是具体实现方法。

bool WinsockInitialized()
{
    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s == INVALID_SOCKET){
        return false;
    }

    closesocket(s);
    return true;
}

int main()
{
    //...
    if ( !WinsockInitialized() )
       // Init winsock here...

    // Carry on as normal.
    // ...         
}

不过这并不是必须的。在任何时候调用WSAStartup都是非常安全的。同时,在每次成功调用WSAStartup()后,使用匹配的调用WSACleanup()也是安全的。

例如:

// socket calls here would be an error, not initialized
WSAStartup(...)
// socket calls here OK

WSAStartup(...)
// more socket calls OK

WSACleanup()
// socket calls OK

WSACleanup()

// more socket calls error, not initialized

1
在任何时候调用WSAStartup都是不安全的。来自MSDN的解释是:“WSAStartup函数通常会导致加载特定协议的辅助DLL。因此,在应用程序DLL的DllMain函数中不应该调用WSAStartup函数。这可能会导致死锁。” - czz
3
如果socket()函数失败并返回除WSANOTINITIALISED之外的任何错误代码,WinsockInitialized()函数仍然会返回true,这是不正确的。根据MSDN文档,socket()函数有13个可能的错误代码。无论如何,进行WSAGetLastError()检查是多余的,因为socket()函数要么成功,要么失败,检查错误代码不会改变结果。下面是翻译后的代码:bool WinsockInitialized() { SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { if (WSAGetLastError() != WSANOTINITIALISED) { return false; } } closesocket(s); return true; } - Remy Lebeau

5
  • 不,无法判断WSAStartup()是否已经被调用。

  • 是的,在单个进程中可以多次调用WSAStartup(),只要请求的版本由WinSock DLL支持。调用WSAStartup()WSACleanup()必须平衡。

  • WinSock初始化是一个协商过程;您负责验证WSAStartup()返回的信息,以确保它满足您应用程序的要求。

  • 现有套接字不会受到后续WSAStartup()调用的影响。

  • 允许使用不同的WinSock版本的多个套接字。

更多信息请参见WSAStartup()文档


除此之外,我发现只要WSACleanup调用的次数与成功的WSAStartup调用的次数相匹配,那么调用WSACleanup就不会影响其他套接字调用。当然,前提是您不要调用太多次WSACleanup。 - hookenz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接