为什么有用于 socket()、connect()、send() 等的 WSA 挂件,但没有用于 closesocket() 的 WSA 挂件?
我将尝试用几个例子来解释我的意思:
- socket() -> WSASocket()
- 连接() -> WSAConnect()
- 发送() -> WSASend()
- sendto() ->; WSASendTo()
- recv() ->; WSARecv()
- recvfrom() ->; WSARecvFrom()
- ...
- closesocket() -> WSA???()
这并不是什么重要的事情,但仍然让我头疼。
I'm going to try to explain what I mean using a few examples:
- socket() -> WSASocket()
- connect() -> WSAConnect()
- send() -> WSASend()
- sendto() -> WSASendTo()
- recv() -> WSARecv()
- recvfrom() -> WSARecvFrom()
- ...
- closesocket() -> WSA???()
This is nothing that matters much, but is still something that gives me a splitting headache.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
要理解这一点,您必须意识到 Winsock 是在 20 世纪 90 年代初创建的,当时 Windows 3.x 恐龙还横行地球。
Windows 套接字(“Winsock”)API 镜像了大多数 BSD 套接字 API:两者都提供给定的功能,并且都执行相同的操作。因此,
socket()
在这两个 API 下是相同的调用。虽然有些地方存在细微差别,但没有什么比基于 BSD 套接字的其他系统(例如 Linux 和 OS X)的网络编程差异更大了。除了实现通用基础 API 之外,Winsock API 还提供了许多对 BSD 套接字的扩展。许多函数的名称与原始函数类似,但带有
WSA
前缀,其他所有函数均采用驼峰式大小写形式。这些纯粹是原始功能的扩展版本,而不是它们的替代品。您可以根据是否需要扩展功能以及您的程序是否必须可移植到仅提供 BSD 套接字 API 的系统来选择使用哪一种。例如,WSASocket()
采用与socket()
相同的参数以及与其他 Winsock 扩展有关的三个附加参数。如果您不需要扩展,那么调用socket()
并没有真正的损失,而且您还可以获得可移植性的好处。除了这些简单的扩展之外,还有一些没有直接 BSD 等效项的 Winsock 扩展,例如
WSAAsyncSelect()
。与 Unixy 系统的程序相比,这些通常与 Windows 程序的编写方式的差异有关。在这种特殊情况下,WSAAsyncSelect()
的存在是为了更轻松地编写使用套接字的单线程 GUI 程序,而网络 I/O 不会阻塞 GUI,反之亦然。这在今天很有用,但对于 Windows 3.1 时代的 Winsock 的成功绝对至关重要,因为当时没有线程或其他有用的多处理和 IPC 机制。这样就只剩下一些奇怪的东西了,比如
closesocket()
和ioctlsocket()
。closesocket()
与close(2)
相同code> 在 POSIX/Unix 下,不同之处在于它只接受套接字,而不接受文件句柄。这是更名的部分原因,但真正的原因来自我上面提到的 20 世纪 90 年代初期的历史问题。在那些日子里,一些 Windows 编译器 - 有更多可用 当时 比今天 — 包含 POSIX API 等效项,以方便将代码从其他平台移植到 Windows。这些功能非常有限,并且不包括套接字支持,但尽管如此,当时的 Windows 上的close()
函数名称仍被认为是“已采用”的。现在不再是这样了,但 Winsock 是其历史的产物,现在无法更改。ioctlsocket()
与ioctl()
的情况类似。一个很大的区别是,与ioctl()
在 Unix 系统上的功能相比,ioctlsocket()
在 Windows 上的功能受到很大限制。它的存在只是为了向 Windows 提供一些与网络相关的设施,最初的 Winsock 创建者认为这些设施在 BSD 套接字 API 中很有用。多年来,在 Unixy 系统上可以使用套接字和 ioctl() 执行但不能使用 ioctlsocket() 执行的大部分操作已通过其他 API 添加到 Windows,仅其中一个其中是WSAIoctl()
。我为 Winsock 程序员常见问题解答(我维护的)详细介绍了这一切。另一篇相关文章是“BSD 套接字兼容性”。
To understand this, you have to realize that Winsock was created in the early 1990s, back when the Windows 3.x dinosaur roamed the earth.
The Windows Sockets ("Winsock") API mirrors most of the BSD sockets API: where both provide a given function, both do the same thing. So,
socket()
is the same call under both APIs. There are minor differences in places, but nothing bigger than the differences in network programming for other systems based on BSD sockets, such as Linux and OS X.In addition to implementing that common base API, the Winsock API also provides many extensions to BSD sockets. Many have names similar to the original functions, but with a
WSA
prefix and camel-case for everything else. These are purely extended versions of the original functions, not replacements for them. You pick which one to use depending on whether you need the extended functionality and whether your program has to be portable to systems that provide only the BSD sockets API. For instance,WSASocket()
takes the same parameters assocket()
plus three additional ones which have to do with other Winsock extensions. If you do not need the extensions, there is no real penalty to callingsocket()
instead, and you get a portability benefit besides.In addition to these simple extensions, there are Winsock extensions that have no direct BSD equivalent, such as
WSAAsyncSelect()
. These generally have to do with differences in the way Windows programs are written, as compared to programs for Unixy systems. In this particular case,WSAAsyncSelect()
exists to make it easier to write single-threaded GUI programs that use sockets without network I/O blocking the GUI or vice versa. This is useful today, but absolutely critical to Winsock's success back in the Windows 3.1 days, which didn't have threads or other useful multiprocessing and IPC mechanisms.That leaves only a few oddballs like
closesocket()
andioctlsocket()
.closesocket()
is the same asclose(2)
under POSIX/Unix, except that it only takes sockets, not file handles. That's part of the reason for the name change, but the real reasons come from that early-1990s history issue I brought up above. In those days, some Windows compilers — there were more available then than today — included POSIX API equivalents to ease porting code from other platforms to Windows. Such features were very limited, and didn't include sockets support, but nevertheless, theclose()
function name was considered "taken" on Windows at that time. It isn't true any more, but Winsock is a product of its history and can't be changed now.The story for
ioctlsocket()
vs.ioctl()
is similar. One big difference is thatioctlsocket()
is greatly limited on Windows as compared to whatioctl()
can do on a Unix system. It exists only to provide Windows with a few network-related facilities that the original Winsock creators thought useful in the BSD sockets API. Over the years, much of what you can do with sockets andioctl()
on Unixy systems but not withioctlsocket()
has been added to Windows through other APIs, just one of which isWSAIoctl()
.I've written an article on "The History of Winsock" for the Winsock Programmer's FAQ (which I maintain) that goes into more detail on all this. Another relevant article is "BSD Sockets Compatibility."
closesocket 仅在 Windows 上可用,我不知道他们为什么不遵守 WSA 公约。如果它真的让你烦恼,你可以制作自己的包装器来调用 closesocket。
正如 WSASocket 中提到的,对 closesocket 的调用应该被制作。
closesocket is only available on Windows, I'm not sure why they didn't follow the WSA convention there though. If it really bothers you though you can make your own wrapper that calls closesocket.
As mentioned in WSASocket a call to closesocket should be made.
这是在 MSDN 文档中编写的:
重命名函数
在两种情况下,需要重命名 Berkeley Sockets 中使用的函数,以避免与其他 Microsoft Windows API 函数发生冲突。
Close 和 Closesocket
套接字由 Berkeley 套接字中的标准文件描述符表示,因此 close 函数可用于关闭套接字以及常规文件。虽然 Windows Sockets 中没有任何内容可以阻止实现使用常规文件句柄来识别套接字,但也没有什么需要它。在 Windows 上,必须使用 closesocket 例程。在 Windows 上,使用 close 函数关闭套接字是不正确的,并且本规范未定义这样做的效果。
Ioctl 和 Ioctlsocket/WSAIoctl
各种 C 语言运行时系统将 IOCTL 用于与 Windows 套接字无关的目的。因此,ioctlsocket 函数和 WSAIoctl 函数被定义为处理 Berkeley Software Distribution 中由 IOCTL 和 fcntl 执行的套接字函数。
This is written in the MSDN documentation:
Renamed Functions
In two cases it was necessary to rename functions that are used in Berkeley Sockets in order to avoid clashes with other Microsoft Windows API functions.
Close and Closesocket
Sockets are represented by standard file descriptors in Berkeley Sockets, so the close function can be used to close sockets as well as regular files. While nothing in Windows Sockets prevents an implementation from using regular file handles to identify sockets, nothing requires it either. On Windows, sockets must be closed by using the closesocket routine. ON Windows, using the close function to close a socket is incorrect and the effects of doing so are undefined by this specification.
Ioctl and Ioctlsocket/WSAIoctl
Various C language run-time systems use the IOCTLs for purposes unrelated to Windows Sockets. As a consequence, the ioctlsocket function and the WSAIoctl function were defined to handle socket functions that were performed by IOCTL and fcntl in the Berkeley Software Distribution.
为了完整起见,人们应该注意到,无论是关于网络、文件、时间/日期还是 ANSI C/POSIX API 的任何其他部分,微软都花费了大量的精力来确保其专有的几代 Windows API 与 Unix API(早在 Windows 之前就存在)不兼容。
微软在 HTML (IE)、HTTP (IIS)、OpenDocuments (MS-Word) 等中也使用了相同的策略。因此,通常的借口是,它是偶然的(或者只是出于“创新”的愿望)疑。
看看 C# 在多大程度上是 Java 的(糟糕的)副本——同时设法完全不兼容(函数名称非常接近,即使不相同,但参数的数量或它们的顺序是不同的)。
现在你知道为什么你首先要问这个问题了。
For the sake of completeness, one should notice that whether it was about networking, files, time / dates or any other part of the ANSI C / POSIX APIs, MICROSOFT has spent a great deal of energy to make sure that its proprietary generations of Windows APIs are incompatible with the Unix APIs (that existed far before Windows).
The same strategy is used by MICROSOFT with HTML (IE), HTTP (IIS), OpenDocuments (MS-Word), etc. so the usual excuse that it is accidental (or only motivated by the desire to 'innovate') is more than doubtful.
Look at how much C# is a (bad) copy of Java - while at the same time managing to be completely incompatible (the function names are very close if not identical, but the number of parameters -or their order- is different).
Now you know why you had to ask this question in the first place.