Почему существуют подвески WSA для сокетов(), connect(), send() и т.д., Но не для closesocket()?
Я попытаюсь объяснить, что я имею в виду, используя несколько примеров:
- socket() → WSASocket()
- connect() → WSAConnect()
- отправить() → WSASend()
- sendto() → WSASendTo()
- recv() → WSARecv()
- recvfrom() → WSARecvFrom()
- ...
- closeesocket() → WSA???()
Это не имеет большого значения, но все же это то, что дает мне головную боль.
Ответы
Ответ 1
closesocket доступен только в Windows, я не уверен, почему они не придерживались соглашения WSA там. Если это действительно беспокоит вас, хотя вы можете сделать свою собственную оболочку, которая вызывает closesocket.
Как упоминалось в WSASocket, должен быть сделан вызов closesocket.
Ответ 2
Чтобы понять это, вы должны понять, что Winsock был создан в начале 1990-х, когда динозавр Windows 3.x бродил по земле.
API-интерфейсы Windows ( "Winsock" ) отражают большинство API-интерфейсов BSD: где обе предоставляют заданную функцию, обе делают то же самое. Таким образом, socket()
- это тот же вызов в обоих API. В местах есть небольшие различия, но не что иное, как различия в сетевом программировании для других систем, основанных на сокетах BSD, таких как Linux и OS X.
В дополнение к реализации этого базового API API Winsock также предоставляет множество расширений для сокетов BSD. У многих есть имена, похожие на исходные функции, но с префиксом WSA
и верблюжьим футляром для всего остального. Это просто расширенные версии исходных функций, а не их замены. Вы выбираете, какой из них использовать, в зависимости от того, нужна ли вам расширенная функциональность и должна ли ваша программа переноситься в системы, которые предоставляют только API-интерфейсы BSD. Например, WSASocket()
принимает те же параметры, что и socket()
плюс три дополнительных, которые связаны с другими расширениями Winsock. Если вам не нужны расширения, нет реального штрафа за вызов socket()
вместо этого, и вы получите преимущество переносимости, кроме того.
В дополнение к этим простым расширениям существуют расширения Winsock, которые не имеют прямого эквивалента BSD, например WSAAsyncSelect()
. Как правило, это связано с различиями в способе написания программ Windows по сравнению с программами для Unixy-систем. В этом конкретном случае существует WSAAsyncSelect()
, чтобы упростить запись однопоточных графических программ, которые используют сокеты без сетевого ввода-вывода, блокирующего графический интерфейс или наоборот. Это полезно сегодня, но абсолютно важно для успеха Winsock в дни Windows 3.1, у которых не было ни потоков, ни других полезных механизмов многопроцессорности и IPC.
Это оставляет только несколько странных вещей, таких как closesocket()
и ioctlsocket()
.
closesocket()
совпадает с close(2)
под POSIX/Unix, за исключением того, что он принимает только сокеты, а не файлы. Эта часть причины изменения имени, но настоящие причины исходят из той проблемы истории начала 1990-х годов, которую я поднял выше. В те дни некоторые компиляторы Windows:— были больше доступно затем, чем сегодня. включая эквиваленты POSIX API, чтобы облегчить перенос кода с других платформ на Windows. Такие функции были очень ограниченными и не включали поддержку сокетов, но, тем не менее, имя функции close()
в то время считалось "взятым" в Windows. Это уже не так, но Winsock является продуктом его истории и теперь не может быть изменен.
История для ioctlsocket()
vs. ioctl()
аналогична. Одно большое различие заключается в том, что ioctlsocket()
сильно ограничен в Windows по сравнению с тем, что ioctl()
может делать в системе Unix. Он существует только для обеспечения Windows несколькими сетевыми средствами, которые оригинальные создатели Winsock считали полезными в API-интерфейсах BSD. На протяжении многих лет большая часть того, что вы можете делать с сокетами и ioctl()
в системах Unixy, но не с ioctlsocket()
, была добавлена в Windows через другие API, только один из которых - WSAIoctl()
.
Я написал статью о История Winsock для Часто задаваемые вопросы программиста Winsock (который я поддерживаю), который более подробно описывает все это. Другая соответствующая статья - "совместимость с BSD Sockets.
Ответ 3
Это написано в документации MSDN:
В двух случаях необходимо было переименовать функции, которые используются в Berkeley Sockets, чтобы избежать столкновений с другими функциями Microsoft Windows API.
Закрытие и закрытие
Сокеты представлены стандартными файловыми дескрипторами в Berkeley Sockets, поэтому функция закрыть может использоваться для закрытия сокетов, а также обычных файлов. Хотя ничто в Windows Sockets не позволяет реализации использовать обычные дескрипторы файлов для идентификации сокетов, ничто не требует этого. В Windows сокеты должны быть закрыты с помощью closesocket. В Windows с использованием функции закрыть, чтобы закрыть сокет, является неправильным, и последствия этого: undefined по этой спецификации.
Ioctl и Ioctlsocket/WSAIoctl
Различные системы времени исполнения на языке C используют IOCTL для целей, не связанных с Windows Sockets. Как следствие, функция ioctlsocket и функция WSAIoctl были определенные для обработки функций сокетов, которые выполнялись с помощью IOCTL и fcntl в распределении программного обеспечения Berkeley.
Ответ 4
Для полноты нужно заметить, что независимо от того, были ли они связаны с сетью, файлами, временем/датами или любой другой частью API ANSI C/POSIX, MICROSOFT потратил много сил, чтобы убедиться в том, что его собственная собственность поколения API Windows несовместимы с Unix-API (которые существовали задолго до Windows).
Та же стратегия используется MICROSOFT с HTML (IE), HTTP (IIS), OpenDocuments (MS-Word) и т.д., поэтому обычное оправдание, что это случайное (или только мотивированное желанием "внедрить новшество" ) более чем сомнительно.
Посмотрите, насколько С# является (плохой) копией Java - и в то же время управляется полностью несовместимо (имена функций очень близки, если не идентичны, но количество параметров - или их порядок - различно).
Теперь вы знаете, почему вы должны были задать этот вопрос в первую очередь.