跨平台sockets

我知道,Windows不使用UNIX套接字,而Mac OS则使用UNIX套接字。 在此之前,我的软件是跨平台的,没有任何代码更改。 但现在我想要它做一些网络通信。 我知道POSIX套接字,但我对Windows的信息一无所知。 目标是实现一个简单的跨平台套接字服务器。

能否请您解释POSIX和Winsock套接字之间的区别以及如何编写跨平台网络代码?

WinSock与POSIX套接字

WinSock和POSIX套接字以类似的方式工作 – 主要是因为Windows套接字最初基于BSD的代码 :

虽然这些专有的BSD衍生产品在很大程度上被20世纪90年代的UNIX System V Release 4和OSF / 1系统所取代(两者都包含BSD代码并且是其他现代Unix系统的基础),后来的BSD版本为几个开放提供了基础。源开发项目,如FreeBSD,OpenBSD,NetBSD,Darwin或PC-BSD,正在进行中。 反过来,它们全部或部分地包含在现代专有操作系统中,例如Microsoft Windows中的TCP / IP(仅限IPv4)网络代码以及Apple OS X和iOS的大部分基础。

但是,如果要编写“socket-library-agnostic”代码,则需要处理一些不同的事情。

注意:以下示例已在Windows XP(x86)和Debian测试(AMD64)上使用Code :: Blocks和GCC进行了测试。

头文件和lib文件是不同的

您需要包含不同的头文件,具体取决于您是否使用Windows:

#ifdef _WIN32 /* See http://stackoverflow.com/questions/12765743/getaddrinfo-on-win32 */ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 /* Windows XP. */ #endif #include  #include  #else /* Assume that any non-Windows platform uses POSIX-style sockets instead. */ #include  #include  #include  /* Needed for getaddrinfo() and freeaddrinfo() */ #include  /* Needed for close() */ #endif 

您还需要在Windows上链接Ws2_32 lib文件。

WinSock需要初始化和清理。

下面的函数说明了如何初始化WinSock v1.1并在之后进行清理:

 int sockInit(void) { #ifdef _WIN32 WSADATA wsa_data; return WSAStartup(MAKEWORD(1,1), &wsa_data); #else return 0; #endif } int sockQuit(void) { #ifdef _WIN32 return WSACleanup(); #else return 0; #endif } 

Winsock上的套接字句柄是UNSIGNED

对于POSIX样式的套接字,您只需使用int来存储套接字句柄。 无效的套接字由负值表示。

但是, WinSock套接字是UNSIGNED整数 ,使用特殊常量( INVALID_SOCKET )而不是负数。

您可以通过在POSIX上键入SOCKET作为int并隐藏宏或函数后面的“有效套接字”检查来抽象差异。

套接字以不同方式关闭

以下function说明了不同之处:

 /* Note: For POSIX, typedef SOCKET as an int. */ int sockClose(SOCKET sock) { int status = 0; #ifdef _WIN32 status = shutdown(sock, SD_BOTH); if (status == 0) { status = closesocket(sock); } #else status = shutdown(sock, SHUT_RDWR); if (status == 0) { status = close(sock); } #endif return status; } 

但总的来说,它们非常相似。

如果您坚持使用“常用”函数(例如send()recv() )并避免特定于平台的东西(例如WSAWaitForMultipleEvents() )那么您应该没问题。

有许多库和工具包支持跨平台套接字,根据您正在做的事情,您可以使用(仅举几例):

  • OpenSSL的
  • apache可移植运行时
  • libtcl

如果您不希望依赖外部库,则上述所有软件包都具有相当宽松的许可证,因此您可以将其代码用作参考。

在所有平台上同样支持构建套接字服务器所需的常规套接字(AF_INET地址族中的套接字)。

不要将它们与Unix套接字(AF_UNIX地址族中的套接字)混淆 – 这种套接字对于Unix世界非常具体,并且用于高度特定的目标。 对于简单的套接字服务器应用程序,您永远不需要它们。

我还可以建议plibsys库:适用于Windows和UNIX系统(请参阅项目页面上的完整列表)和各种编译器。 支持IPv4和IPv6。 它有测试,您可以在其中查看用法示例。 该库本身轻巧便携。