Why did Microsoft implement sockets differently?

Andrew Szeto picture Andrew Szeto · Aug 9, 2009 · Viewed 8.2k times · Source

I'm currently in the middle of a project involving sockets, and I just use Linux's sys/socket.h file. Cue the port to Microsoft, and realizing that Winsock is different. I guess I have two questions.

First, what're the main differences between the two implementations? Is there an easy way to "translate" them? A link to a guide would be greatly appreciated, because you guys can probably get me better quality links than Google.

Second, why did Microsoft do this? What was their motivation? Why didn't they just keep the same implementation as everyone else?

Answer

Warren Young picture Warren Young · Aug 9, 2009

The Winsock Programmer's FAQ has a section on this, BSD Sockets Compatibility. (Disclosure: I'm the FAQ's maintainer.)

I didn't really cover the whys and wherefores in that article, so:

  • winsock.h vs sys/socket.h, arpa/inet.h, netinet/in.h, etc.: This I actually find an improvement. It's all one tight set of functionality, so why not have all the definitions for it in a single header?

  • close() vs. closesocket(): Back in the Windows 3 days when Winsock was invented, Windows C++ compilers all had some kind of POSIX API wrapper to provide some basic level of portability, including close(). These just called down into the compiler's stdio implementation, since DOS and Win16 didn't have a unified I/O mechanism like Unices do. You can't just call close() on a descriptor in Win16 and have it work independent of whether it's a file, socket, pipe, whatever. Win32 existed at the same time as Winsock was being invented as part of NT 3.5, and it fixes this, but making Winsock available only on NT derivatives would have made MS irrelevant on the Internet until Windows XP. MS can be slow to the game, but not that slow. Bottom line, anything in BSD sockets that uses POSIX mechanisms that conflicted with existing APIs provided by the C++ compilers that targeted it just couldn't be in Winsock. They had to give the same functionality a new name.

  • WSA*(): This is just added functionality, providing functionality that BSD sockets doesn't. A lot of it is really nice, and it'd be nice to see similar mechanisms across all Unices, but that's not going to happen any time soon. There are competing mechanisms, like aio*(), but that isn't available across all Unices, much less portable to Windows. You can just ignore it and stick to the base sockets APIs, though this isn't always the best choice when porting to Windows.

  • errno vs. WSAGetLastError(): errno is part of Standard C, but the error values are up to the C implementation. Keep in mind that Winsock in the beginning was not a Microsoft-specific thing. DOS and Windows didn't start off having standard network APIs. This was provided by third parties, who all got together and invented Winsock, with Microsoft involved. The initial Winsock stacks were all third-party. They couldn't write the spec to be overwriting the C RTL's errno value, for several reasons. These error values belonged to the vendor-provided winsock.dll, a whole different world from the C RTL.

  • WSAStartup(), WSACleanup(): Again this is due to the fact that winsock.dll was initially a third-party provided thing, which interfaced with some underlying network stack that isn't part of the OS. Also, there's the Win16 aspect of things: Win16 couldn't see that a program just died and clean up its allocated resources automatically. You had to explicitly release everything before the program exited, or they'd be leaked.

  • Lack of readv(), etc.: This didn't make sense in the third-party/Win16 world where Winsock was born.