跨平台套接字

时间:2015-01-19 15:21:12

标签: c sockets

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

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

4 个答案:

答案 0 :(得分:59)

WinSock与POSIX套接字

WinSockPOSIX套接字的工作方式类似 - 主要是因为Windows sockets were originally based on code from 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 <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

您还需要在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 sockets are UNSIGNED integers使用了一个特殊常量(INVALID_SOCKET)而不是负数。

您可以在POSIX上将typedef SOCKET抽象为int,并在宏或函数后面隐藏“有效套接字”检查。

套接字以不同方式关闭

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

/* 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())那么您应该没问题。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

有许多库和工具包支持跨平台套接字,具体取决于您正在做什么,您可以使用(仅举几例):

  • OpenSSL的
  • apache portable runtime
  • libtcl

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

答案 3 :(得分:1)

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

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