2.5.2 平台独立的定义
由于Sockets API 库和Winsock库在某些方面有差异,所以需要创建一种方法,使得无论采用哪种实现方法,代码都可以运行。由于各种API几乎相同,所以这很容易办到。
在这一点上,可以有若干种选择方案,例如,任何时候想要关闭套接字时都可以如下所示这么做。
#ifdef WIN32
closesocket( sock );
#else
close( sock );
#endif
这种方法稍微有点乱,除非是将关闭套接字的代码单独分离出来,在第4章中创建一个套接字包装器后就是这么做的。但是,暂时采用的这种方法是一种比较笨也不太容易理解的方法。下面介绍另一种方法,将这些代码称为“代码块2.2(Code Block 2.2)”:
// 代码块2.2 —— 为交互兼容性进行重新定义和全局化处理
#ifdef WIN32 // Windows 95 及以上
WSADATA g_wsadata; // Winsock数据持有者
#define CloseSocket closesocket
#define GetSocketError WSAGetLastError
#define StartSocketLib WSAStartup( MAKEWORD( 2, 2 ), &g_wsadata );
#define CloseSocketLib WSACleanup();
#ifndef socklen_t
typedef int socklen_t;
#endif
#else // UNIX/Linux
#define CloseSocket close
#define GetSocketError errno
#define StartSocketLib {}
#define CloseSocketLib {}
#endif
// 结束代码块 2.2 —— 为交互兼容性进行重新定义和全局化处理
因为Winsock需要一个WSADATA结构,所以在WIN32分支代码中定义了一个WSADATA结构。接下来的4行在Winsock和Sockets API中有差异。在Windows分支的代码段中,宏CloseSocket只是closesocket的另一个名称(注意区分大小写);而在Linux分支的代码段中,它是close的另一个名称。GetSocketError的情况与此相同,根据不同的系统,它的别名可能是WSAGetLastError,也可能是errno。
最后两行定义了套接字库的初始化和停止阶段,在Winsock中有内容,但在Socket API中则没有内容。因此,StartSocketLib的Windows版本称为WSAStartup;而UNIX版本则根本没有任何内容(只是一对空括号)。
Windows代码块另外还有3行代码。这是因为有些旧的Winsock版本中没有定义socklen_t数据类型。因此,只要函数检测到它不存在,就可以简单地将它定义为int。许多套接字函数都需要socklen_t。






