跨平台套接字
Cross-platform sockets
我知道,Windows 不使用 UNIX 套接字,而 Mac OS 使用。到目前为止,我的软件是跨平台的,没有任何代码更改。但是现在我想让它做一些网络通信。我知道 POSIX 套接字,但我对 Windows' 套接字一无所知。目标是实现一个简单的跨平台套接字服务器。
能否请您向我解释一下 POSIX 和 Winsock 套接字之间的区别以及我如何编写跨平台网络代码?
有很多库和工具包支持跨平台套接字,根据您的用途,您可以使用(仅举几例):
- openssl
- apache 可移植运行时
- libtcl
如果你不想依赖外部库,以上所有包都有相当宽松的许可证,所以你可以使用他们的代码作为参考。
构建套接字服务器所需的常规套接字(AF_INET 地址族中的套接字)在所有平台上都得到同等支持。
不要将它们与 Unix 套接字(AF_UNIX 地址族中的那些)混淆 - 这样的套接字对于 Unix 世界是高度特定的,并且用于高度特定的目标。对于简单的套接字服务器应用程序,您永远不需要它们。
WinSock 与 POSIX 套接字
WinSock and POSIX sockets work in a similar manner - mainly because Windows sockets were originally based on code from BSD:
Although these proprietary BSD derivatives were largely superseded by the UNIX System V Release 4 and OSF/1 systems in the 1990s (both of which incorporated BSD code and are the basis of other modern Unix systems), later BSD releases provided a basis for several open source development projects, e.g. FreeBSD, OpenBSD, NetBSD, Darwin or PC-BSD, that are ongoing. These, in turn, have been incorporated in whole or in part in modern proprietary operating systems, e.g. the TCP/IP (IPv4 only) networking code in Microsoft Windows and most of the foundation of Apple's OS X and iOS.
但是,如果您想编写 "socket-library-agnostic" 代码,则需要以不同的方式处理一些事情。
注意:以下示例已在 Windows XP (x86) 和 Debian 测试 (AMD64) 上使用 Code::Blocks 和 GCC 进行了测试。
头文件和lib文件不同
您需要包含不同的头文件,具体取决于您是否使用 Windows:
#ifdef _WIN32
/* See */
#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
您还需要 link 和 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 上未签名
对于POSIX风格的套接字,您可以简单地使用int
来存储套接字句柄。无效套接字用负值表示。
然而,WinSock sockets are UNSIGNED integers,用一个特殊的常数(INVALID_SOCKET
)代替负数。
您可以通过 typedef
在 POSIX 上将 SOCKET 作为 int
并将 "valid socket" 检查隐藏在宏或函数后面来抽象差异。
套接字的关闭方式不同
下面的函数说明了差异:
/* 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;
}
但总的来说,它们非常相似。
如果您坚持使用 "common" 函数(例如 send()
或 recv()
)并避免平台特定的东西(例如 WSAWaitForMultipleEvents()
),那么您应该没问题.
我还可以推荐 plibsys 库:可以在 Windows 和 UNIX 系统(请参阅项目页面上的完整列表)上使用各种编译器。支持 IPv4 和 IPv6。它有测试,您可以在其中查看使用示例。该库本身是轻量级和可移植的。
我知道,Windows 不使用 UNIX 套接字,而 Mac OS 使用。到目前为止,我的软件是跨平台的,没有任何代码更改。但是现在我想让它做一些网络通信。我知道 POSIX 套接字,但我对 Windows' 套接字一无所知。目标是实现一个简单的跨平台套接字服务器。
能否请您向我解释一下 POSIX 和 Winsock 套接字之间的区别以及我如何编写跨平台网络代码?
有很多库和工具包支持跨平台套接字,根据您的用途,您可以使用(仅举几例):
- openssl
- apache 可移植运行时
- libtcl
如果你不想依赖外部库,以上所有包都有相当宽松的许可证,所以你可以使用他们的代码作为参考。
构建套接字服务器所需的常规套接字(AF_INET 地址族中的套接字)在所有平台上都得到同等支持。
不要将它们与 Unix 套接字(AF_UNIX 地址族中的那些)混淆 - 这样的套接字对于 Unix 世界是高度特定的,并且用于高度特定的目标。对于简单的套接字服务器应用程序,您永远不需要它们。
WinSock 与 POSIX 套接字
WinSock and POSIX sockets work in a similar manner - mainly because Windows sockets were originally based on code from BSD:
Although these proprietary BSD derivatives were largely superseded by the UNIX System V Release 4 and OSF/1 systems in the 1990s (both of which incorporated BSD code and are the basis of other modern Unix systems), later BSD releases provided a basis for several open source development projects, e.g. FreeBSD, OpenBSD, NetBSD, Darwin or PC-BSD, that are ongoing. These, in turn, have been incorporated in whole or in part in modern proprietary operating systems, e.g. the TCP/IP (IPv4 only) networking code in Microsoft Windows and most of the foundation of Apple's OS X and iOS.
但是,如果您想编写 "socket-library-agnostic" 代码,则需要以不同的方式处理一些事情。
注意:以下示例已在 Windows XP (x86) 和 Debian 测试 (AMD64) 上使用 Code::Blocks 和 GCC 进行了测试。
头文件和lib文件不同
您需要包含不同的头文件,具体取决于您是否使用 Windows:
#ifdef _WIN32
/* See */
#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
您还需要 link 和 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 上未签名
对于POSIX风格的套接字,您可以简单地使用int
来存储套接字句柄。无效套接字用负值表示。
然而,WinSock sockets are UNSIGNED integers,用一个特殊的常数(INVALID_SOCKET
)代替负数。
您可以通过 typedef
在 POSIX 上将 SOCKET 作为 int
并将 "valid socket" 检查隐藏在宏或函数后面来抽象差异。
套接字的关闭方式不同
下面的函数说明了差异:
/* 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;
}
但总的来说,它们非常相似。
如果您坚持使用 "common" 函数(例如 send()
或 recv()
)并避免平台特定的东西(例如 WSAWaitForMultipleEvents()
),那么您应该没问题.
我还可以推荐 plibsys 库:可以在 Windows 和 UNIX 系统(请参阅项目页面上的完整列表)上使用各种编译器。支持 IPv4 和 IPv6。它有测试,您可以在其中查看使用示例。该库本身是轻量级和可移植的。