C++ 为什么socket()、connect()和send()等都有WSA挂起,而closesocket()却没有?

C++ 为什么socket()、connect()和send()等都有WSA挂起,而closesocket()却没有?,c++,winapi,sockets,winsock,C++,Winapi,Sockets,Winsock,我将试着用几个例子来解释我的意思: 套接字()->WSASocket() connect()->WSAConnect() send()->WSASend() sendto()->WSASendTo() recv()->WSARecv() recvfrom()->WSARecvFrom() closesocket()->WSA???() 这没什么大不了的,但仍然让我头痛不已。只在Windows上可用,但我不知道他们为什么不遵循WSA惯例。如果它真的困扰你,尽管你可以自己做一个叫做closes

我将试着用几个例子来解释我的意思:

  • 套接字()->WSASocket()
  • connect()->WSAConnect()
  • send()->WSASend()
  • sendto()->WSASendTo()
  • recv()->WSARecv()
  • recvfrom()->WSARecvFrom()
  • closesocket()->WSA???()
这没什么大不了的,但仍然让我头痛不已。

只在Windows上可用,但我不知道他们为什么不遵循WSA惯例。如果它真的困扰你,尽管你可以自己做一个叫做closesocket的包装器


正如在调用closesocket时提到的那样。

要理解这一点,您必须意识到Winsock创建于20世纪90年代初,当时Windows 3.x恐龙在地球上漫游

Windows Sockets(“Winsock”)API反映了大多数BSD Sockets API:两者都提供给定的函数,它们都做相同的事情。因此,
socket()
在两个API下是相同的调用。在不同的地方有一些细微的差异,但没有什么比基于BSD套接字的其他系统(如Linux和OSX)的网络编程的差异更大

除了实现该公共基础API之外,Winsock API还为BSD套接字提供了许多扩展。许多函数的名称与原始函数相似,但都带有
WSA
前缀和驼峰大小写。这些是原始函数的纯扩展版本,不是它们的替代品。您可以根据是否需要扩展功能以及程序是否必须可移植到仅提供BSD套接字API的系统来选择使用哪一个。例如,
WSASocket()
采用与
socket()
相同的参数,外加三个与其他Winsock扩展相关的额外参数。如果您不需要这些扩展,那么调用
socket()
并不会带来真正的损失,而且您还可以获得可移植性方面的好处

除了这些简单的扩展之外,还有一些Winsock扩展没有直接的BSD等价物,例如
WSAAsyncSelect()
。与Unixy系统的程序相比,这些通常与Windows程序的编写方式不同有关。在这种特殊情况下,
WSAAsyncSelect()
的存在使编写使用套接字的单线程GUI程序变得更容易,而不需要网络I/O阻塞GUI,反之亦然。这在今天很有用,但对于Winsock在Windows 3.1时代的成功来说绝对至关重要,因为Windows 3.1没有线程或其他有用的多处理和IPC机制

这只剩下一些奇怪的东西,比如
closesocket()
ioctlsocket()

closesocket()
与POSIX/Unix下的相同,只是它只接受套接字,不接受文件句柄。这是改名的部分原因,但真正的原因来自我上面提到的20世纪90年代早期的历史问题。在那些日子里,一些Windows编译器(比今天的编译器还多)包含了POSIXAPI等价物,以便于将代码从其他平台移植到Windows。这些功能非常有限,并且不包括套接字支持,但是,当时在Windows上,
close()
函数名被认为是“采用”的。这不再是事实,但Winsock是其历史的产物,现在无法改变

ioctlsocket()
ioctl()
的情况类似。与Unix系统上的
ioctl()
相比,Windows上的
ioctlsocket()
有很大的不同。它的存在只是为了向Windows提供一些原始Winsock创建者认为在BSD sockets API中有用的网络相关功能。多年来,您可以在Unixy系统上使用Socket和
ioctl()
而不是
ioctlsocket()
执行的大部分操作都是通过其他API添加到Windows中的,其中只有
WSAIoctl()


我已经为(我坚持)写了一篇关于“”的文章,详细介绍了所有这一切。另一篇相关文章是“

为了完整起见,应该注意,无论是关于网络、文件、时间/日期还是ANSI C/POSIX API的任何其他部分,MICROSOFT都花费了大量精力来确保其专有的Windows API与Unix API不兼容(远在Windows之前就存在)

微软在HTML(IE)、HTTP(IIS)、OpenDocuments(MS Word)等方面也采用了同样的策略。因此,通常认为这是偶然的(或仅仅是出于“创新”的愿望)的借口是值得怀疑的

看看C#在多大程度上是Java的一个(坏的)副本,同时又设法做到完全不兼容(函数名非常接近,如果不完全相同,但参数的数量——或者它们的顺序——是不同的)


现在您知道了为什么首先要问这个问题。

这写在MSDN文档中:

在两种情况下,有必要重命名Berkeley套接字中使用的函数,以避免与其他Microsoft Windows API函数发生冲突

闭合和闭合插座 套接字由Berkeley Sockets中的标准文件描述符表示,因此close函数可用于关闭套接字以及常规文件。虽然Windows Sockets中没有任何内容阻止实现使用常规文件句柄来识别套接字,但也没有任何内容需要它。在Windows上,套接字必须由使用例程。在Windows上,使用关闭功能关闭套接字是不正确的,并且此规范未定义这样做的效果

Ioctl和Ioctlsocket/WSAIoctl 各种C语言运行时系统将IOCTL用于与Windows套接字无关的目的