跨平台套接字

For*_*Bru 28 c sockets

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

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

GoB*_*sto 67

WinSock与POSIX套接字

WinSockPOSIX套接字以类似的方式工作 - 主要是因为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 Testing(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 <winsock2.h>
  #include <Ws2tcpip.h>
#else
  /* Assume that any non-Windows platform uses POSIX-style sockets instead. */
  #include <sys/socket.h>
  #include <arpa/inet.h>
  #include <netdb.h>  /* Needed for getaddrinfo() and freeaddrinfo() */
  #include <unistd.h> /* Needed for close() */
#endif
Run Code Online (Sandbox Code Playgroud)

您还需要Ws2_32在Windows上链接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
}
Run Code Online (Sandbox Code Playgroud)

Winsock上的套接字句柄是UNSIGNED

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

但是,WinSock套接字是UNSIGNED整数,使用特殊的constant(INVALID_SOCKET)而不是负数.

您可以typedef通过SOCKET int在POSIX上抽象差异,并在宏或函数后面隐藏"有效套接字"检查.

套接字以不同方式关闭

以下功能说明了不同之处:

/* 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;

}
Run Code Online (Sandbox Code Playgroud)

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

如果您坚持使用"常用"功能(例如send()recv())并避免使用平台特定的东西(例如WSAWaitForMultipleEvents()),那么您应该没问题.

  • 另一个区别是 Windows 的“WinSock”不能很好地处理 POSIX 套接字可以正常工作的基本“read()”和“write()”调用。例如,在 WinSock 上调用 write(socket, buffer, bytes) 可能会失败,而在同一套接字上调用 send(socket, buffer, bytes, 0) 则可以正常工作。 (3认同)

Ale*_*kin 6

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