【发布时间】:2014-01-18 02:42:13
【问题描述】:
我想用 C 语言制作一个可在 Windows、Linux 和 osx(最重要)上运行的 TCP 客户端。我在 SO 上找到的代码可能适用于 linux,但不适用于 osx,反之亦然。那么我需要做什么来确保它对所有三个都有效?
谢谢!
【问题讨论】:
-
最简单的路线?搜索并使用已经建立和调试过的跨平台库。
-
你可以使用ACE或BOOST提供的库。
我想用 C 语言制作一个可在 Windows、Linux 和 osx(最重要)上运行的 TCP 客户端。我在 SO 上找到的代码可能适用于 linux,但不适用于 osx,反之亦然。那么我需要做什么来确保它对所有三个都有效?
谢谢!
【问题讨论】:
假设您计划编写代码以使用 BSD 套接字 API,您会发现大多数在 Linux 上运行的 TCP 客户端代码都可以在 MacOS/X 上运行,只需很少或无需修改,反之亦然。
让代码在 Windows 下也能工作有点棘手,因为所需的 #include 不同,并且在许多情况下,Windows 的 TCP 堆栈(又名 WinSock)的行为与 TCP 的行为略有不同其他两个操作系统的堆栈。也就是说,Windows 确实支持大多数 BSD 套接字 API,并且通过一点#ifdef-ing,您可以想出一个可以在所有三个操作系统上正确编译和运行的程序。当然,您需要在所有三个操作系统上进行测试和调试;永远不要仅仅因为某些东西在一个操作系统上运行就认为它可以在任何地方运行。
根据您的程序的特定需求(和您的兴趣),听从 Duck 的建议并找到一个已经为您完成上述工作的网络库可能很有意义;但是,如果您更喜欢“自己动手”,那也是可行的。写入 BSD 套接字 API 的一个好方法是:每当您发现一段代码必须为不同的操作系统编写不同的代码时,将该代码 sn-p 的实现一起隐藏在一个函数中(使用 #ifdef 以便正确的代码会在每个操作系统下编译),这样程序的其余部分就不必再记住如何处理那些令人不快的细节了。这样做足够多的时间,你最终会成为你自己的跨平台网络库的自豪维护者;)
我建议首先让您的程序在 Linux 和/或 OS/X 下运行,一旦您对它感到满意,然后将其移植到 Windows 上。将网络代码移植到 Windows 时需要注意的一些“问题”:
在 Windows 下,您可以 #include windows.h 或 winsock2.h 来获取您需要的网络定义。 (如果你想要更新的 WinSock2 API,你必须包含 winsock2.h,并且总是在 windows.h 的任何#include 之前完成,否则你会得到错误的 API 版本......这是一个真正的马戏团)
在 Windows 下,您必须在执行任何网络操作之前调用 WSAStartup()(如果您忘记了,所有网络调用都会出错)
在 MacOS/X 和 Linux 下,文件描述符和套接字在很大程度上是可互换的(即您可以在 STDIN_FILENO 上选择()等)。在 Windows 下,它们不是。
在 MacOS/X 和 Linux 下,您可以通过检查 errno 找出调用失败的原因。在 Windows 下,您改为调用 WSAGetLastError()。
在 MacOS/X 和 Linux 下,您可以使用 close() 销毁套接字。在 Windows 下,您可以使用 closesocket() 来完成。
在 MacOS/X 和 Linux 下,您可以(如果您选择)在 TCP 套接字上调用 read() 和 write() 来接收/发送数据(分别)。在 Windows 下,这是行不通的,您必须只调用 send() 和 recv()。 (send() 和 recv() 也可以在 MacOS/X 和 Linux 下工作)
要在 Windows 下将套接字设置为非阻塞模式,您必须调用 ioctlsocket(fd, FIONBIO, &mode)。在 MacOS/X 和 Linux 下,您改为调用 fcntl(fd, F_SETFL, flags)。
更多有趣的 Windows 网络陷阱可以在WinSock Lame List 阅读。
【讨论】: