【问题标题】:Cross-platform sockets跨平台插座
【发布时间】:2015-03-17 15:41:27
【问题描述】:

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

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

【问题讨论】:

  • 它超越了纯套接字,但我发现 0mq (ZeroMq) 非常有趣。
  • 我通常做的是在 Cygwin 下使用 POSIX 程序并使用 gcc 编译,然后像这样分发 ;-) 额外的好处:它让我在 Windows 上的生活更轻松。
  • 不幸的是(?)提出建议的问题是explicitly off topic这里。但是,一种解决方案是使用 Cygwin(如果您需要其他类似 Unix 的基础设施)或 Mingw(如果您的程序不需要“假 unix”环境,只需 C 库/API 就足够了)直接构建你的 Unix/Linux 源代码。
  • 这种问题非常有用,抱歉已关闭

标签: c sockets


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    WinSock 与 POSIX 套接字

    WinSockPOSIX 套接字的工作方式相似——主要是因为Windows sockets were originally based on code from BSD

    虽然这些专有的 BSD 衍生产品在 1990 年代被 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
    

    您还需要链接到 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 上通过 typedefing 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()),那么您应该没问题。

    【讨论】:

    • 另一个区别是 Windows 的 WinSock 不能很好地处理基本的 read()write() 调用,而 POSIX 套接字可以正常工作。例如,在 WinSock 上调用 write( socket, buffer, bytes ) 可能会失败,而在完全相同的套接字上调用 send( socket, buffer, bytes, 0 ) 可以正常工作。
    • 你为什么要告诉 OP 链接到 Winsock 2 并告诉他们如何清理 Winsock 1 套接字?
    • @rstackhouse 你升级到清理它
    【解决方案3】:

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

    不要将它们与 Unix 套接字(AF_UNIX 地址系列中的那些)混淆 - 这样的套接字对于 Unix 世界来说是高度特定的,并且用于高度特定的目标。对于简单的套接字服务器应用程序,您永远不需要它们。

    【讨论】:

      【解决方案4】:

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

      • openssl
      • apache 可移植运行时
      • libtcl

      如果您不想依赖外部库,上述所有软件包都有相当宽松的许可证,因此您可以使用它们的代码作为参考。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-22
        • 1970-01-01
        • 2011-04-14
        • 2019-05-15
        • 2019-12-28
        • 1970-01-01
        相关资源
        最近更新 更多