2.5 数据库文件

时间:2021-07-29 11:20:33
2.5 数据库文件
getXbyY()和 WSAAyncGetXByY()这一类的例程是用来得到某种特殊的网络信息的。
getXbyY()例程最初(在第一版的BERKELY UNIX 中)是被设计成一种在文本数据库中查询信
息的机制。虽然Windows Sockets实现可能用不同的方式来得到这些信息,但 Windows Sockets

应用程序要求通过getXbyY()或WSAAyncGetXByY()这一类例程得到的信息是一致。


2.6 与 Berkeley套接口的不同
有一些很有限的地方,Windows Sockets API必须与从严格地坚持Berkeley传统风格中解放
出来。通常这么做是因为在Windows环境中实现的难度。
2.6.1  套接口数据类型和错误数值
Windows Sockets 规范中定义了一个新的数据类型 SOCKET ,这一类型的定义对于将来
Windows Sockets规范的升级是必要的。例如在 Windows NT中把套接口作为文件句柄来使用。

这一类型的定义也保证了应用程序向Win/32 环境的可移植性。因为这一类型会自动地从 16 位
升级到32位。
在UNIX 中所有句柄包括套接口句柄,都是非负的短整数,而且一些应用程序把这一假设
视为真理。 Windows Sockets 句柄则没有这一限制,除了 INVALID_SOCKET 不是一个有效的
套接口外,套接口可以取从0到INVALID_SOCKET-1 之间的任意值。
因为SOCKET类型是unsigned,所以编译已经存在于 UNIX 环境中的应用程序的源代码可能会
导致signed/unsigned数据类型不匹配的警告。
这还意味着,在 socket()例程和 accept()例程返回时,检查是否有错误发生就不应该再使用
把返回值和-1 比较的方法,或判断返回值是否为负(这两种方法在 BSD 中都是很普通,很合
法的途径)。取而代之的是,一个应用程序应该使用常量 INVALID_SOCKET ,该常量已在
WINSOCK.H 中定义。
例如:
  典型的BSD 风格:
  s = socket(...);
  if (s == -1)       /* of s<0 */
 {...}
  更优良的风格:
  s = socket(...);
  if (s == INVALID_SOCKET)
 {...}

2.6.2 select()
函数和 FD_*宏
由于一个套接口不再表示了 UNIX 风格的小的非负的整数, select()函数在 Windows
Sockets API中的实现有一些变化:每一组套接口仍然用 fd_set类型来代表,但是它并不是一个
位掩码。整个组的套接口是用了一个套接口的数组来实现的。为了避免潜在的危险,应用程序
应该坚持用FD_XXX 宏来设置,初始化,清除和检查 fd_set结构。
错误代码- errno,h_errno,WSAGetLastError()
2.6.3 
Windows Sockets实现所设置的错误代码是无法通过 errno变量得到的。另外对于 getXbyY()
这一类的函数,错误代码无法从h_errno变量得到。错误代码可以使用 WSAGetLastError()调用
得到。这一函数在 5.3.11 中讨论。这个函数在 Windows Sockets 实现中是作为 WIN/32 函数
GetLastError()的先导函数(最终是一个别名)。这样做是为了在多线程的进程中为每一线程得
到自己的错误信息提供可靠的保障。
为了保持与BSD 的兼容性,应用程序可以加入以下一行代码:
#define errno WSAGetLastError()
这就保证了用全程的errno变量所写的网络程序代码在单线程环境中可以正确使用。当然,

这样做有许多明显的缺点:如果一个原程序包含了一段代码对套接口和非套接口函数都用 errno
变量来检查错误,那么这种机制将无法工作。此外,一个应用程序不可能为 errno 赋一个新的
值(在Windows Sockets中,WSASetLastError()函数可以做到这一点)。
例如:
典型的BSD 风格:
r = recv(...);
if (r == -1                             /* 但请见下文 */
&& errno == EWOULDBLOCK)
   {...}
更优良的风格:
r = recv(...);
if (r == -1                               /* 但请见下文 */
&& WSAGetLastError() == EWOULDBLOCK)
   {...}
虽然为了兼容性原因,错误常量与 4.3BSD 所提供的一致;应用程序应该尽可能地使用
“WSA”系列错误代码定义。例如,一个更准确的上面程序片断的版本应该是:
r = recv(...);
if (r == -1                                 /* 但请见下文 */
&& WSAGetLastError() == WSAEWOULDBLOCK)
   {...}
2.6.4 
指针
所有应用程序与Windows Sockets使用的指针都必须是 FAR指针,为了方便应用程序开发
者使用,Windows Sockets规范定义了数据类型 LPHOSTENT。
2.6.5  重命名的函数
有两种原因Berkeley套接口中的函数必须重命名以避免与其他的 API冲突:
2.6.5.1 close()
和 closesocket()
在Berkeley套接口中,套接口出现的形式与标准文件描述字相同,所以 close()函数可以用
来和关闭正规文件一样来关闭套接口。虽然在 Windows  Sockets  API 中,没有任何规定阻碍
Windows Sockets实现用文件句柄来标识套接口,但是也没有任何规定要求这么做。套接口描述
字并不认为是和正常文件句柄对应的,而且并不能认为文件操作,例如 read(), write()和 close()

在应用于套接口后不能保证正确工作。套接口必须使用 closesocket()例程来关闭,用 close()例程
来关闭套接口是不正确的,这样做的效果对于 Windows Sockets规范说来也是未知的。
2.6.5.2 ioctl()和 iooctlsocket()
许多 C 语言的运行时系统出于与 Windows  Sockets 无关的目的使用 ioctl()例程,所以
Windows Sockets定义ioctlsocket()例程。它被用于实现 BSD 中用 ioctl()和 fcntl()实现的功能。
2.6.6  阻塞例程和 EINPROGRESS宏
虽然Windows Sockets支持关于套接口的阻塞操作,但是这种应用是被强烈反对的.如果程
序员*使用阻塞模式(例如一个准备移植的已有的程序),那么他应该清楚地知道 Windows
Sockets中阻塞操作的语义。有关细节请参见 4.1.1
2.6.7 Windows Sockets 支持的最大套接口数目
一个特定的 Windows Sockets 提供者所支持的套接口的最大数目是由实现确定的。任何一
个应用程序都不应假设某个待定数目的套接口可用。这一点在 4.3.15 WSAStartup()中会被重申。
而且一个应用程序可以真正使用的套接口的数目和某一特定的实现所支持的数目是完全无关
的。
一个 Windows  Sockets 应用程序可以使用的套接口的最大数目是在编译时由常量
FD_SETSIZE 决定的。这个常量在 select()函数(参见 4.1.18 )中被用来组建 fd_set 结构。在
WINSOCK.H 中缺省值是 64。如果一个应用程序希望能够使用超过 64 个套接口,则编程人员
必须在每一个源文件包含WINSOCK.H 前定义确切的 FD_SET值。有一种方法可以完成这项工
作,就是在工程项目文件中的编译器选项上加入这一定义。例如在使用 Microsoft C 时加入-D
FD_SETSIZE=128作为编译命令的一个命令行参数.要强调的是:FD_SET定义的值对Windows
Sockets实现所支持的套接口的数目并无任何影响。
头文件
2.6.8 
为了方便基于 Berkeley套接口的已有的源代码的移植, Windows Sockets 支持许多 Berkeley 头
文件。这些Berkeley头文件被包含在 WINSOCK.H 中。所以一个 Windows Sockets 应用程序只
需简单的包含WINSOCK.H 就足够了(这也是一种被推荐使用的方法)。