第六章 Windows Socket 2 的扩展特性

这一章将讨论从 Windows Sockets 1.1 到 Windows Socket 2 的主要变动。

同时使用多个传输协议

为了用户能够同时使用多个传输协议,在 Windows Socket 2 中,结构有所改变。在 Windows Sockets 1.1 中,软件开发商所提供的 DLL 实现了 Windows Sockets 的 API 和 TCP/IP 协议栈。Windows Sockets DLL 和底层协议栈的接口是唯一而且独占的。Windows Socket 2 改变了这种模型:它定义了一个 Windows Sockets DLL 和底层协议栈间的标准服务提供接口(SPI)。这使得一个 Windows Sockets DLL 能够同时访问不同软件开发商的多个底层协议栈。此外,Windows Sockets 2 并不象 Windows Sockets 1.1 仅支持 TCP/IP 协议栈。与 Windows 开放系统结构(WOSA)兼容的 Windows Sockets 2 的结构如下图:

W inSock 2 A PI

W inSock 2 传输服务 SPI

W inSock 2 名字空间 SPI

图 6-1:Windows Socket 2 开放系统结构图

注意:16 位的 Windows Sockets 2 应用程序应使用 WS2-16.DLL,而 32 位的Windows Sockets 2 应用程序应使用 WS2-32.DLL。但今后,为了简单起见,它们将都使用 WINSOCK.DLL。这并不会造成任何问题,因为在它们之间并没有任何语

法上的区别。

由于以上的结构,现在已没有必要每个协议栈开发商都提供它们自己的WINSOCK.DLL(甚至这样做也不是期望的)。因为任何一个 WINSOCK.DLL 能够在所有协议栈上工作。因此,WINSOCK.DLL 可以被看作是一个操作系统组件。Microsoft 将在Windows 95 和Windows NT 上提供一个32 位的WINSOCK.DLL。Intel 公司目前正在打算提供 Windows 3.1 和 Windows 3.11 上的 Windows Sockets 2 兼容的 16 位 WINSOCK.DLL。

与 Windows Socket 1.1 应用程序的向后兼容性

Windows Socket 2 与 Windows Sockets 1.1 在两个基础上向后兼容:源码和二进制代码。这就实现了 Windows Sockets 应用程序和任何版本的 Windows Sockets 实现之间的最大的互操作性,而且也减少了 Windows Sockets 应用程序使用者,网络协议栈提供者和服务提供者的许多痛苦。现有的 Windows Sockets

1.1 兼容的应用程序可以在 Windows Sockets 2 实现上不加修改的运行,只要有一个 TCP/IP 协议栈被安装。

源码的兼容性

Windows Sockets 2 中的源码兼容性意味着所有的 Windows Sockets 1.1 版的 API 在 Windows Sockets 2 中都被保留了下来。这意味着现有的 Windows Sockets 1.1 应用程序的原程序可以被简单的移植到 Windows Sockets 2 系统上运行。程序员需要做的只是包含新的头文件-WINSOCK2.H 和简单的与合适的Windows Sockets 2 函数库的连接。应用程序开发者应该把这种工作看作是完全转向 Windows Sockets 2 的第一步,因为有许多方式可以使用 Windows Sockets 2 中的新函数来提高原来的 Windows Sockets 1.1 应用程序的运行性能。

二进制兼容性

在设计 Windows Sockets 2 时的一个主要目标就是使得现有的 Windows Sockets 1.1 应用程序在二进制级别上能够不加修改的应用于 Windows Sockets 2 之上。由于 Windows Sockets 1.1 是基于 TCP/IP 上的,二进制兼容性就要求Windows Sockets 2 系统提供基于 TCP/IP 上的 Windows Sockets 2 的传输和名字解析服务。为了 Windows Sockets 1.1 应用程序能在这种意义上运行,Windows Sockets 2 系统提供了一个附加的组件-Windows Sockets 1.1 的 DLL。Windows Sockets 2 安装时的提示保证了在终端机用户引进 Windows Sockets 2 系统时不会对已有的 Windows Sockets 软件环境有任何影响。

第六章 Windows Socket 2 的扩展特性 - 图1

第六章 Windows Socket 2 的扩展特性 - 图2W inSock 1.1 A PI

A PI

W inSock 2 A PI

A PI

W inS ock 2 SPI’s

图 6-2:与 Windows Sockets 1.1 二进制兼容性结构图

一个完全的 Windows Sockets 1.1 二进制兼容的必要的前提是在系统上已经安装了至少一个 TCP/IP 协议栈并且在 Windows Sockets 2 中做了注册。Windows Sockets 1.1 目前通过 WSAData 结构中的某些元素来得到关于底层 TCP/IP 协议栈的信息(例如通过 WSAStartup()函数调用),这些信息包括 iMaxSockets, iMaxUdpDg 和 IPVendorInfo。但是在 Windows Sockets 2 中,应用程序应该知道忽略这些信息,因为这些值不能统一地适用于所有协议栈。不过 DLL 必须仍然提供这些值以免破坏 Windows Sockets 1.1 的应用程序。这些信息只能从(因此也只能应用于)缺省的 TCP/IP 服务提供者得到。缺省的 TCP/IP 服务提供者是由WSAEnumProtocols()调用返回的 PROTOCOL_INFO 结构缓冲区的第一条 TCP/IP 协议栈。

在 Windows Sockets 中注册传输协议

要使 Windows Sockets 能够利用一个传输协议,该传输协议必须在系统上安装并且在 Windows Sockets 中注册。Windows Sockets 2 的 DLL 包含了一组 API 来完成这个注册过程。这个注册过程包括建立一个新的注册和取消一个已有的注册。在建立新的注册时,调用者(假设是协议栈开发商的安装程序)必须提供一组或多组完整的关于协议的信息,这些信息将被用来填充 PROTOCOL_INFO 结构。

使用多个协议

一个应用程序可以通过 WSAEnumProtocols()功能调用来得到目前有多少个传输协议可以使用,并且得到与每个传输协议相关的信息,这些信息包含在PROTOCOL_INFO 结构中。然而,某些传输协议可能表现出多种行为。例如 SPX 是基于消息的(发送者发送的消息的边界在网络上被保留了),但是接收的一方可以选择忽略这些边界并把套接口作为一个字节流来对待。这样就很合理地导致了SPX 有两个不同的 PROTOCOL_INFO 结构条目,每一个条目对应了一种行为。

在 Windows Sockets 1 中仅有一个地址族(AF_INET),它包含了数量不多的一些众所周知的套接口类型和协议标识符。这在 Windows Sockets 2 中已经有所改变。除了现有的地址族,套接口类型和协议标识符为了兼容性原因被保留以外,Windows Sockets 2 加入了许多唯一的但是可能并不为大家所知的地址族, 套接口类型和协议标识符。不为大家所知并不意味着会对应用程序开发造成问题,因为一个企图做成协议无关的应用程序应该在对自身合适的基础上选择协议而不应该依赖于某个分配给它的特定的套接口类型或协议类型值。PROTOCOL_INFO 结构中包含的通讯性质指明了协议的合适性(例如:基于消息的对应于基于字节流的,可靠的对应于不可靠的,等等)。基于合适性原则选取协议而不使用某个特定的协议名和套接口类型。

对于客户机/服务器模型,服务器一端的应用程序最好能够在所有合适的传输协议上建立监听套接口。这样,客户机一端的应用程序就可以通过任何合适的传输协议来与服务器一端的应用程序建立连接。这样做可以使得一个客户机应用程序易于移植。例如一台运行于 LAN 上的台式机的客户机应用程序在转到运行于无线网上的笔记本计算机时就不用作任何改变。

select()函数应用中关于多个服务提供者的限制

在 Windows Sockets 2 中,函数 select()使用 FD_SET 仅能应用于和单个服务提供者相连的套接口。但是这并不限制一个应用程序使用多个服务提供者打开多个套接口。如果应用程序开发者喜欢使用非阻塞方式编程,那么可以使用WSAAsyncSelect()函数。由于该函数需要一个套接口描述字作为输入参数,那么与该套接口相连的服务提供者是很重要的。如果一个应用程序需要在一组跨越多个服务提供者的套接口上使用带有阻塞语法的函数,那么应该使用WSAWaitForMultipleEvents()函数。应用程序也可以使用 WSAEventSelect()函数。该函数允许应用程序把 FD_XXX 网络事件和一个事件对象相连接,并且在该事件对象中处理网络事件(这一模式将在下文讨论)。

协议无关的名字解析

Windows Sockets 2 包含了应用程序可以使用的多种标准化的网络名字服务。Windows Sockets 2 应用程序并不需要理解与名字服务相关的许多迥异的接口(例如 DNS,NIS,X.5000,SAP 等等)。本书的 4.2 介绍了这一主题,并对API 做了详细介绍。

重叠 I/O 和事件对象

Windows Sockets 2 引入了重叠 I/O 的概念并且要求所有的传输协议提供者都支持这一功能。重叠 I/O 仅能在由 WSASocket()函数打开的套接口上使用(使用 WSA_FLAG_OVERLAPPED 标记)。这种方式的使用将采用 Win32 建立的模型。

对于接收,应用程序使用 WSARecv()函数或 WSARecvFrom()函数来提供存放接收数据的缓冲区。如果数据在网络接收以前,应用程序已经提供了一个或多个数据缓冲区,那么接收的数据就可以立即被存放进用户缓冲区。这样可以省去使用 recv()函数和 recvfrom()函数时需要进行的拷贝工作。如果在应用程序提供数据缓冲区时已经有数据到来,那么接收的数据将被立即拷贝进用户缓冲区。如果数据到来时,应用程序没有提供接收缓冲区,那么网络将回到我们熟悉的同步操作方式-传送来的数据将被存放进内部缓冲区,直到应用程序发出了接收调用并且提供了接收缓冲区,这时接收的数据就被拷贝进接收缓冲区。这种做法会有一个例外:就是当应用程序使用 setsockopt()函数把接收缓冲区长度置为了 0。在这种情况下,对于可靠传输协议,只有在应用程序提供了接收数据缓冲区后, 数据才会被接收;而对于不可靠传输协议,数据将会丢失。

对于发送的一方,应用程序使用 WSASend()函数或 WSASendTo()函数提供一个指向已填充的数据缓冲区的指针。应用程序不应在网络使用完该缓冲区的数据以前以任何方式破坏该缓冲区的数据。

重叠发送和接收调用会立即返回。如果返回值是 0,那么表明了 I/O 操作已经完成,对应的完成指示也已经可以得到。如果返回值是 SOCKET_ERROR,并且错误代码是 WSA_IO_PENDING,那么表明重叠操作已经被成功地初始化,今后发送缓冲区被用完或者接收缓冲区被填满时,将会有完成指示。任何其他的错误代码表明了初始化没有成功,今后也不会有什么完成指示。

发送操作和接收操作都可以被重叠使用。接收函数可以被多次调用,发出接收缓冲区,准备接收到来的数据。发送函数也可以被多次调用,组成一个发送缓冲区队列。要注意的是,应用程序可以通过按顺序提供发送缓冲区来确保一系列重叠发送操作的顺序,但是对应的完成指示有可能是按照另外的顺序排列的。同样的,在接收数据的一方,缓冲区是按照被提供的顺序填充的,但是完成指示也可能按照另外的顺序排列。

WSAIoctl()函数(ioctolsocket()函数的增强版本)还可以使用重叠 I/O 操

作的延迟完成特性。

事件对象

重叠I/O 概念的引入需要建立一个机制使得应用程序能够正确的把发送和接收事件与今后它们完成时的指示相连接。在 Windows Sockets 2 中,这一点是通过事件对象实现的,它采用了 Win32 事件的模型。Windows Sockets 事件对象是一个相当简单的结构,它可以被创建,关闭,设置,清除,等待和检查。它们的主要用处是使得应用程序能够阻塞并等待直到一个或多个事件对象被设置。

应用程序可以使用 WSACreateEvent()函数来得到一个事件对象句柄,这个句柄可以作为以后的重叠发送和接收函数的输入参数(WSASend(),WSASendTo(), WSARecv(),WSARecvFrom())。事件对象在创建时被清除,在相关的重叠 I/O 操作完成时由传输协议提供者设置(或者成功,或者出错)。每个被WSACreateEvent() 函数创建的事件对象都必须有对应的 WSACloseEvent()函数释放它。

WSAEventSelect()函数把一个或多个 FD_XXX 网络事件与一个事件对象连接。这将在 2.6 中讨论。

在 32 位环境中,与事件对象相关的函数,包括 WSACreateEvent(), WSACloseEvent(),WSASetEvent(),WSAResetEvent(), WSAWaitForMultipleEvent()和 WSAGetOverlappedResult(),都被直接映射到对应的 Win32 函数,例如没有 WSA 前缀的同名函数。

接收操作完成指示

为了提供给应用程序适当的灵活性,Windows Sockets 2 为接收操作完成指示提供了多个选项。它们包括:等待(阻塞)事件对象,检查事件对象和套接口I/O 完成例程。

阻塞并且等待完成指示。

应用程序可以使用 WSAWaitForMultipleEvents()函数来选择阻塞程序直到一个或多个事件对象被设置。在 Win16 实现中,这种方式将使用一个阻塞钩子, 就象在标准的阻塞套接口操作时一样。在 Win32 实现中,进程或线程会被真正地阻塞。因为 Windows Sockets 2 事件对象被实现成 Win32 事件,所以 Win32 函数WaitForMultipleObjects()也可以使用。这在线程需要阻塞套接口和非套接口事件时将会非常有用处。

检查完成指示

应用程序如果不希望使用阻塞方式,它可以使用WSAGetOverlappedResults() 函数来检查与某个特定的事件对象相连的完成状态。该函数检查重叠操作是否完成,如果完成的话,处理重叠操作的出错信息,使得该信息在 WSAGetLastError() 函数调用时可以得到。

使用套接口 I/O 操作完成例程

所有的用来初始化重叠 I/O 操作的函数(WSASend(),WSASentTo(), WSARecv(),WSARecvFrom())都把 lpCompletionRoutine 作为输入参数。这是一个应用程序定义的函数指针,在重叠 I/O 操作完成时可以被调用。

在 Win16 环境中,回调函数有可能在 VMM 环境(有时也被称作中断环境)下被激活。传送对时间要求较高的数据(例如视频或音频数据)在这种低延时,占先方式下接受这种指示会很方便。但是应用程序必须知道,在这种特殊情况下, 只要很少一部分运行时和 Windows 库函数可以被调用。作为一条规则,应用程序必须把自己限制在一套 Windows 文挡说明的在一个多媒体定时回调函数中可以被安全调用的运行时函数库。

在 Windows 95 和 Windows NT 中,完成例程与 Win32 文件 I/O 完成例程遵循着同样的规则。在所有的环境中,传输协议允许应用程序以完成例程的方式唤起发送和接收操作,而且保证对于给定的一个套接口,I/O 完成例程不会嵌套。这就允许了在一个占先的环境中进行对时间敏感的数据的传送。

WSAOVERLAPPED 的细节

WSAOVERLAPPED 结构提供了一个重叠I/O 操作的初始化和它将来的如何被完成之间的通讯媒体。WSAOVERLAPPED 结构被设计成与 Win32 中的 OVERLAPPED 结构兼容:

typedef struct WSAOVERLAPPED {

DWORD

DWORD

Internal;

InternalHigh;

//

//

reserved

reserved

DWORD

Offset;

//

ignored

DWORD

OffsetHigh;

//

ignored

WSAEVENT

hEvent;

} WSAOVERLAPPED, LPWSAOVERLAPPED;

Internal 这一个保留的域是由重叠 I/O 实现的实体内部使用的。对

于使用类文件方式创建套接口的传输服务提供者,这一域是被底层的操作系统使用的;对于其他的传输服务提供者(那些创建伪句柄的),可以视需要使用这个域。

InternalHigh 这一个保留的域是由重叠 I/O 实现的实体内部使用的。对于使用类文件方式创建套接口的传输服务提供者,这一域是被底层的操作系统使用的;对于其他的传输服务提供者(那些创建伪句柄的),可以视需要使用这个域。

Offset 由于套接口没有文件偏移量的概念,应用程序可以视需要使用这个域。

OffsetHigh 由于套接口没有文件偏移量的概念,应用程序可以视需要使用这个域。

hEvent 如果一个重叠的 I/O 操作在被调用时没有使用 I/O 操作完成例程(lpCompletionRoutine 为空指针),那么这个域必须包含一个有效的WSAEVENT 对象的句柄,否则(lpCompletionRoutine 不为空指针),应用程序可以视需要使用这个域。

使用事件对象异步通知

为了适应一些应用程序例如精灵程序或者某些没有用户界面的服务程序(因此不使用窗口句柄),Windows Socket 2 提供了 WSAEventSelect()函数和WSAEnumNetworkEvents()函数。WSAEventSelect()函数和 WSAAyncSelect()函数很类似,区别仅在于当一个 FD_XXX 网络事件发生时,WSAEventSelect()函数将导致一个应用程序指定的事件对象被设置,而 WSAAyncSelect()将导致一条Windows 消息被发送(例如 FD_READ,FD_WRITE 等等)。

此外,传输服务提供者会记住每个特定的 FD_XXX 网络事件的发生。应用程序可以调用 WSAEnumNetworkEvents()函数把目前的网络事件记忆拷贝到应用程序提供的缓冲区中,并且自动清除网络事件记忆。如果需要,应用程序还可以把某个特定的事件对象和网络事件记忆一起清除。

服务的质量(QOS)

Windows Sockets 2 中的 QOS 机制是从 Craig Partridge 在 RFC 1363 中描述的流规格引入的。这一概念可以大致描述如下:

流规格描述了一个网络上单向数据流的性质的集合。应用程序可以在调用WSAConnect()函数发出连接请求或者使用 WSAIoctl()函数等其他 QOS 命令时, 把一对流规格和一个套接口连接(一个规范对应了一个方向)。流规格以参数方式声明了应用程序所要求的服务的级别,并且为应用程序适应不同的网络条件提供了一套反馈机制-如果应用程序要求的服务级别不能达到,应用程序是否愿意松动它的要求。

Windows Sockets 2 中 QOS 的使用模型如下:

对于基于连接的传输服务,应用程序可以很方便的在使用 WSAConnect()函数提出连接请求时规定它所要求的服务质量(QOS)。要注意的是:如果应用程序在调用 WSAConnect()时 QOS 参数不为空,那么对于基于连接的套接口,任何预先设置的 QOS 都会被覆盖。如果 WSAConnect()函数成功返回,应用程序就会知道它所要求的 QOS 已经被网络接受,那么应用程序就可以随意的使用这个套接口进行数据交换。如果连接操作由于资源有限而失败,应用程序应该适当地降低它所要求的服务质量或者干脆就放弃操作。

在每次连接企图之后(不论成功与否),传输服务提供者都会更新 flow_spec 结构,以便尽可能地指明目前的网络条件。如果应用程序所要求的服务质量仅仅包含了一些传输服务提供者必须满足的缺省值,那么这种更新会是很有用处的。应用程序可以利用这些关于当前网络条件的信息来指导自己使用网络,例如今后的 QOS 要求。然而应用程序应该注意的是,传输服务提供者在不断更新的flow_spec 结构中提供的信息仅仅是一个参考,它们只不过是粗略的估计。应用程序应该很小心的解释这些数据。

无连接的套接口也可以使用 WSAConnect()函数为一个指定的通讯规定特定的 QOS 级别。WSAIoctl()函数也可以用来规定初始的 QOS 要求,或者用来今后的QOS 协商。

即使是一个流规格已经建立,网络的情况也有可能改变,或者通讯的一方可能提出了 QOS 重协商的要求,这将导致可以得到的服务级别的降低或者提高。Windows Sockets 2 引入了一个通知机制。它使用了一般的 WS 通知方式(FD_QOS 和 FD_GROUP_QOS 事件)来告诉应用程序 QOS 级别已经改变了。一般服务提供者只在当前的服务级别和上一次报告有很大区别(通常是逆向的),并且有可能会影响到应用程序时才发出 FD_QOS/FD_GROUP_QOS 通知。应用程序应该使用WSAIoctl()函数来得到当前的状态并且检查服务等级的那些方面有了变化。如果当前的 QOS 级别是不可接受的,应用程序应该调整自己以去适应当前的状态,试图重新协商或者关闭套接口。

Windows Sockets 2 推荐的流规格把 QOS 特性划分为如下几个方面:

  1. 源通讯描述:应用程序的通讯事件以什么方式被送入网络。

  2. 延时性:最大延时和可接受的延时变化。

  3. 需要保证的服务级别:应用程序是否要求对服务质量的绝对保证。

  4. 费用:这一项是为将来可以决定有意义的费用时保留的。

  5. 服务提供者特定的参数:流规格可以根据具体的提供者扩展。

    1. 套接口组

Windows Sockets 2 引入了一个所谓套接口组的概念。它允许应用程序(或者一组共同工作的应用程序)通知底层的服务提供者一组特定的套接口是相关的,它们享有一些特定的性质。组的特性包括了组内单个套接口之间的相关特性和整个组的服务规范的特性。

需要在网络上传输多媒体数据的应用程序会因为在所使用的一组套接口上建立联系而得到好处。至少这可以告诉服务提供者正在传输的数据流的一些相关性质。例如,一个会议应用程序希望传送音频数据的套接口比传送视频数据的套接口有更高的优先级。此外,一些传输服务提供者(例如数字电话和 ATM)可以利用服务规范的组特性来决定底层调用或者线路连接的性质。通过应用程序指明套接口组及其特性,服务提供者可以以最大效率应用这些套接口。

WSASocket()函数和 WSAAccept()函数可以用来在创建一个新的套接口的同时显式的创建或者加入套接口组。getsockopt()函数可以用来得到套接口所属套接口组的标志。

共享套接口

为了在进程间共享套接口,Windows Sockets 2 引入了WSADuplicateSocket()函数。共享套接口是通过对底层的套接口创建附加的套接口描述字实现的。该函数的输入是本地的套接口描述字和目标进程的句柄。它返回一个仅在目标进程中有效的新的套接口描述字(目标进程有可能就是原始进程)。这一机制既可以在单线程 Windows 版本(例如 Windows 3.1)中使用,也可以在占先的多线程 Windows版本(例如 Windows 95 和 Windows NT)中使用。要注意的是,套接口可以在一个进程的不同线程中共享而不需要使用 WSADuplicateSocket()函数,因为一个套接口描述字在进程的所有线程中都有效。

基于一个共享套接口的两个或者单个套接口描述字应该独立地使用套接口I/O。然而 Windows Sockets 没有实现任何共享控制。因此,在一个共享套接口上协调它们的操作是应用程序的责任。一个典型的使用共享套接口的例子是,有一个进程专门负责创建套接口和建立连接,并把套接口交给其他负责信息交换的进程。由于重新创建的是套接口描述字而不是底层的套接口,所以一切与套接口相关的状态对于所有套接口描述字都是相同的。例如对一个套接口描述字应用setsockopt()操作后,对所有的套接口描述字应用 getsockopt()操作都可以看到这一变化。一个进程有可能调用 closesocket()函数关闭一个复制的套接口描述字,于是该描述字就被清除了,然而,底层的套接口并不会被关闭,底层的套

接口将一直保持打开,直到最后的一个套接口描述字被关闭。 选择对共享套接口的通知可以使用 WSAAsyncSelect()函数和

WSAEventSelect()函数。对任何共享的套接口描述字发出这些调用将会取消在这一套接口上的所有注册事件,无论先前的注册使用了那个套接口描述字。因此, 如果应用程序想使进程 A 接收 FD_READ 事件,进程 B 接收 FD_WRITE 事件,这是做不到的。如果应用程序确实需要使用这种紧密的协调方式,我们建议应用程序开发者使用线程而不要使用进程。

连接建立和拆除的高级函数

WSAAccept()函数允许应用程序在接受连接请求以前得到请求者的信息,例如请求者的 ID,QOS 等等。这一点是通过对一个应用程序提供的条件函数的回调来实现的。如果服务提供者支持的话,在 WSAConnect()函数的参数或者WSAAccept()函数的条件函数说明的用户对用户的数据可以在连接建立的时候传送到对方。

在连接拆除时,如果协议支持的话,也可以在通讯的端点间交换用户数据。需要提出拆除连接的通讯端点可以调用WSASendDisconnect()函数声明没有要传送的数据并启动连接拆除过程。对于某些协议,这一拆除过程包括了从发起拆除连接的一方发送拆除数据。在接收到远端已经启动了连接拆除过程的通知后(通常是 FD_CLOSE),应用程序可以调用 WSARecvDisconnect()函数接收某些拆除数据。

为了解释如何使用拆除数据,我们考虑如下的场景:在客户机/服务器模型中,通常是由客户机决定何时终止套接口的连接。在终止连接的同时,它通过拆除数据提供和服务器连接的次数。服务器也提供它和所有客户机的总的连接次数。这一过程如下所示:

客户机端 服务器端

  1. 调用 WSASendDisconnect()函数终止对话并提供总的交互次数。

  2. 得到 FD_CLOSE,recv()函数返回 0,或者 WSARecv()函数返回WSAEDISCON

    错误表示优雅的关闭。

  3. 调用 WSARecvDisconnect() 函数来得到客户机的总的交互次数。

  4. 计算累积授权次数。

  5. 调用 WSASendDisconnect() 函数来传送累积授权次数。

  6. 接收 FD_CLOSE 指示 (5’) 调用 closesocket()函数。

  7. 调 用 WSARecvDisconnect() 函数来接收并存放累积授权次数。

  8. 调用 closesocket()函数。

注意:步骤(5’)必须在步骤(5)之后执行,但是与步骤(6),(7)或(8)没有时间联系.

扩展的字节顺序转换例程

Windows Sockets 2 并不假设对于所有协议,网络字节顺序都是正确的。所以 Windows Sockets 2 提供了一套把 16 位或者 32 位数字转换到网络字节顺序或者从网络字节顺序转换的例程。这些例程通常有一个整型的输入参数,它通常是一个常量,指明了需要的网络字节顺序是什么(目前或者是 big_endian,或者是 little_endian)。同时,每个协议的 PROTOCOL_INFO 结构包含一个域指明了协议对应的网络字节顺序,它可以用来作为字节顺序转换例程的输入参数。

分散/聚集方式 I/O

WSASend(),WSASendTo(),WSARecv()和 WSARecvFrom()函数都以应用程序缓冲区数组作为输入参数,因此它们可以进行分散/聚集方式(向量方式)的 I/O 操作。如果应用程序需要传送的信息除了信息体外还包含了一个或多个固定长度的头时,这种操作是很有用的。这些头在发送之前不需要由应用程序连接到一个连续的缓冲区中。同样的,在接收时,这些头会自动的分离到各自的缓冲区中。

如果接收时应用程序提供了多个缓冲区,当有数据到来时,操作就结束了, 不论提供的缓冲区是否都被使用了。

协议无关的多点通讯

Windows Sockets 2 支持基本的数据传输以一般的方式使用不同的传输协议。Windows Sockets 2 也支持应用程序以一般的方式使用传输协议的多点通讯能力。

目前的多点通讯实现在节点加入一个多点对话的方式上有很大的不同。例如,是否有一个特殊的节点被指定为中心节点或者就是根节点;数据是在所有节点之间交换还是只在根节点和它的叶节点之间交换。Windows Sockets 2 中的PROTOCOL_INFO 结构允许一个协议声明它的多点通讯的各种特性。通过检查这些特性,应用程序可以知道在使用 Windows Sockets 2 函数设置,使用和拆除多点

对话时应该遵循那一种协定。

Windows Sockets 2 中为支持多点通讯而作的增加如下:

  • PROTOCOL_INFO 结构中的两个特性位。

  • 为 WSASocket()的参数 iflags 定义的四个标志。

  • 一个新函数-WSAJoinLeaf(),它用来在多点对话中加入一个叶节点。

  • 两个 WSAIoctl()的命令代码。

    1. 新增套接口选项一览

Windows Sockets 2 新增的套接口选项归纳如下:

选项值

类型

含义

缺省值

SO_GROUP_ID

GROUP

套接口所属的套接口组

NULL

SO_GROUP_PRIORITY

int

套接口在套接口组中的

0

相对优先级

SO_MAX_MSG_SIZE int 对于基于消息的套接口, 决定于

这一选项指明了一个消 实现息的最大长度。对于基

于流的套接口,这一选项没有任何意义。

SO_PROTOCOL_INFO struct 描述捆绑到套接口的协 决定于PROTOCOL 议的信息。 协议

_INFO

PVD_CONFIG

char

一个包含了服务提供者

决定于

FAR *

配置信息的不透明的数

实现

据结构对象。

新增套接口 ioctl 操作代码

Windows Sockets 2 新增的 ioctl 操作代码归纳如下。WSAIoctol()函数支持所有为 ioctlsocket()函数定义的操作代码。

操作代码 输入类型 输出类型 含义

SIO_ASSOCIATE_HANDLE 决定于伴随 没有使用。 把套接口与一个指定

的 API。 的伴随接口连接。

SIO_ENABLE_CIRCULAR_ 没有使用 没有使用 允许循环队列。QUEUEING

SIO_FIND_ROUTE struct 没有使用 请求找到对应于指定

sockaddr 地址的例程。

SIO_FLUSH 没有使用 没有使用 废除当前发送队列的内容。

SIO_GET_BROADCAST_ 没有使用 没有使用 得到特定协议的广播地址,

该地址可以使用在 send() 函数和 WSASend()函数中。

SIO_GET_QOS

议。

没有使用

QOS 得到套接口当前的流协

SIO_GET_GROUP_QOS

没有使用

QOS 得到套接口所属套接口组

流协议。

SIO_MULTIPOINT_LOOK

BOOL

没有使用 决定多点对话的数据是否

本地主机的同一套接口接收。

SIO_MULTICAST_SCOPE

间。

int

没有使用

定义允许多方传送的空

SIO_SET_QOS

议。

QOS

没有使用

为套接口建立新的流协

SIO_SET_GROUP_QOS

QOS

没有使用

为套接口所属套接口组建

新的流协议。

SIO_TRANSLATE_HANDLE int 决定于伴 得到一个上下文有效的套接口

随 API 对应的句柄。

新增函数一览

Windows Sockets 2 新增的函数列在下表中:

WSAAccept() accept()函数的扩展版本,它支持条件接收和套接口分组。

WSACloseEvent() 释放一个事件对象。

WSAConnect() connect()函数的扩展版本,它支持连接数据交换和 QOS 规范。

WSACreateEvent() 创 建 一 个 事 件 对 象 。 WSADuplicateSocket() 为一个共享套接口创建一个新的套接口描述字。

WSAEnumNetworkEvents() 检查是否有网络事件发生。WSAEnumProtocols() 得到每个可以使用的协议的信息。WSAEventSelect() 把网络事件和一个事件对象连接。WSAGetOverlappedResu() 得到重叠操作的完成状态。WSAGetQOSByName() 对于一个传输协议服务名字提供相应的 QOS 参数。

WSAHtonl() htonl()函数的扩展版本。

WSAHtons() htons()函数的扩展版本。

WSAIoctl() ioctlsocket()函数的允许重叠操作的版本。

WSAJoinLeaf() 在多点对话中加入一个叶节点。

WSANtohl() ntohl()函数的扩展版本。

WSANtohs() ntohs()函数的扩展版本。

WSARecv() recv()函数的扩展版本。它支持分散/聚集 I/O 和重叠套接口操作。

WSARecvDisconnect() 终止套接口的接收操作。如果套接口是基于连接的,得到拆除数据。

WSARecvFrom() recvfrom()函数的扩展版本。它支持分散/聚集I/O 和重叠套接口操作。

WSAResetEvent() 重新初始化一个数据对象。

WSASend() send()函数的或者版本。它支持分散/聚集 I/O

和重叠套接口操作。

WSASendDisconnect() 启动一系列拆除套接口连接的操作,并且可以选择发送拆除数据。

WSASendTo() sendto()函数的扩展版本。它支持分散/聚集I/O 和重叠套接口操作。

WSASetEvent() 设置一个数据对象。

WSASocket() socket()函数的扩展版本。它以一个PROTOCOL_INFO 结构作为输入参数,并且允许创建重叠套接口。它还允许创建套接口组。

WSAWaitForMultipleEvents() 阻塞多个事件对象。

第七章 Windows Sockets 2 扩展库函数简要参考

WSAAccept()

简述:根据条件函数的返回值有条件地接受连接,同时(可选地)创建和/或加入一个套接口组。

SOCKET WSAAPI WSAAccept ( SOCKET s, struct sockaddr FAR * addr, int FAR * addrlen, LPCONDITIONPROC lpfnCondition, DWORD dwCallbackData );

s:标识一个套接口的描述字,该套接口在 listen()后监听连接。addr:(可选)指针,指向存放通讯层所知的连接实体地址的缓冲区。addr 参数的具体格式由套接口创建时产生的地址族决定。 addrlen:(可选)指针,指向存放 addr 地址长度的整形数。lpfnCondition:(可选的)用户提供的条件函数的进程实例地址。该函数根据参数传入的调用者信息作出接受或拒绝的决定,并通过给结果参数赋予特定的值来(可选地)创建和/或加入一个套接口组。 dwCallbackData:作为条件函数参数返回给应用程序的回调数据。WinSock 不分析该参数。

返回值:

若无错误发生,WSAAccept()函数返回所接受套接口的描述字。否则的话,将返回 INVALID_SOCKET 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

addrlen 参数引用的整形数初始时包含了 addr 参数所指向的空间数,在调用返回时包含了返回地址的实际长度。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAECONNREFUSED 根据条件函数的返回值(CF_REJECT)强制拒绝连接请求。

WSAENETDOWN 网络子系统失效。

WSAEFAULT addrlen 参数太小(小于 sockaddr 结构的大小),或者

lpfnCondition 并不是用户空间的一部分。

WSAEINTR 通过 WSACancelBlockingCall()函数取消(阻塞)调用。WSAEINPROGRESS 一个阻塞 WinSock 调用正在进行。

WSAEINVAL WSAAccept()调用前未执行 listen()调用;条件函数中的 g 参数非法;条件函数的返回值非法;套接口处于非法状态。

WSAEMFILE WSAAccept()调用时排队队列非空,且无可用套接口描述字。

WSAENOBUFS 无可用缓冲区空间。WSAENOTSOCK 描述字不是一个套接口。

WSAEOPNOTSUPP 所引用的套接口不是支持面向连接服务类型的。WSATRY_AGAIN 根据条件函数的返回值(CF_DEFER) ,连接请求被推迟。WSAEWOULDBLOCK 套接口标志为非阻塞,无连接请求供接受。

WSAEACCES 被推迟的连接请求超时或撤销。

另请参阅:accept(), bind(), connect(), getsockopt(),listen(), select(), socket(), SAAsyncSelect(), WSAConnect().

WSACloseEvent()

简述:关闭一个开放的事件对象句柄。#include <winsock2.h>

BOOL WSAAPI WSACloseEvent( WSAEVENT hEvent ); hEvent:标识一个开放的事件对象句柄。

返回值:

如果函数顺利完成,返回值为真 TRUE。如果失败,返回值为假 FALSE。可用WSAGetLastError()调用获取更多的错误信息。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSA_INVALID_HANDLE hEvent 不是一个合法的事件对象句柄。

另请参阅: WSACreateEvent(), WSAEnumNetworkEvents(),WSAEventSelect(),

WSAGetOverlappedResult(),WSARecv(), WSARecvFrom(), WSAResetEvent(),WSASend(), WSASendTo(), WSASetEvent(),WSAWaitForMultipleEvents().

WSAConnect()

简述:创建一个与远端的连接,交换连接数据,并根据所提供的流描述确定所需的服务质量。

#include <winsock2.h>

int WSAAPI WSAConnect ( SOCKET s, const struct sockaddr FAR * name,

int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData,

LPQOS lpSQOS, LPQOS lpGQOS );

s:用于描述一个未连接套接口的描述字。name:欲与套接口连接的远端名字。namelen:名字长度。

lpCallerData:指向用户数据的指针,该数据在建立连接时将传送到远端。lpCalleeData:指向用户数据的指针,该数据在建立连接时将从远端传送回本机。

lpSQOS:指向套接口 s 流描述的指针,每个方向一个。lpGQOS:指向套接口组流描述的指针。(如果有套接口组的话)

返回值:

如果无错误发生,WSAConnect()返回 0。否则的话,将返回 INVALID_SOCKET 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

对于阻塞套接口来说,返回值表示连接试图是否成功。

对于非阻塞套接口来说,连接试图不一定马上完成。在这种情况下, WSAConnect()返回 SOCKET_ERROR,且 WSAGetLastError()返回 WSAEWOULDBLOCK. 此时应用程序可以:

1。利用 select()函数,通过检查套接口是否可写来判断连接请求是否完成。或者,

2。如果应用程序已使用 WSAAsyncSelect()函数来确定对连接事件的兴趣,则

当连接操作完成时应用程序将收到 FD _CONNECT 通知。或者,

3。如果应用程序已使用 WSAEventSelect()函数来确定对连接事件的兴趣,则当连接操作完成时相应的事件对象将设置信号。

对于一个非阻塞套接口来说,在连接试图完成之前,任何对该套接口的WSAConnect()调用都将以 WSAEALREADY 错误失败。

如果返回值指出连接试图失败(例如 WSAECONNREFUSED, WSAENETUNREACH, WSAETIMEDOUT)则应用程序可对该套接口再次调用 WSAConnect()函数。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEADDRINUSE 所指地址已被使用。

WSAEINTR 通过 WSACancelBlockingCall()函数中止了阻塞调用。WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAEALREADY 在所指定的套接口上正在进行一个非阻塞的 connect() 或 WSAConnect()调用。

WSAEADDRNOTAVAIL 本地机器上无法获得所指定的地址。WSAEAFNOSUPPORT 所指定地址族中的地址无法与本套接口一起使用。WSAECONNREFUSED 连接试图被拒绝。

WSAEFAULT name 或 namelen 参数不是用户地址空间的一个有效部分;namelen 参数太小; lpCalleeData、 lpSQOS 和 lpGQOS 的缓冲区太小;或者 lpCallerData 的缓冲区太大。

WSAEINVAL 套接口已与一个地址捆绑。

WSAEINVAL 套接口未与一个地址捆绑。

WSAEINVAL s 参数为监听套接口。

WSAEISCONN 套接口已经连接(仅适用于面向连接的套接口)。WSAENETUNREACH 当前无法从本主机联系网络。

WSAENOBUFS 无可用缓冲区,套接口未连接。WSAENOTSOCK 描 述 字 不 是 一 个 套 接 口 。 WSAEOPNOTSUPP lpSQOS 和 lpGQOS 中的流描述无法满足。WSAEPROTONOSUPPORT 服务提供者不支持 lpCallerData 参数。WSAETIMEDOUT 连接试图超时,连接未建立。

WSAEWOULDBLOCK 套接口标志为非阻塞,连接无法立即完成。当套接口用select()函数设置为读时,可调用 select()。

WSAEACCES 由于 setsockopt()时未允许 SO_BROADCAST,无法将一个数据报套接口与一个广播地址连接。

另请参阅: accept(), bind(), connect(), getsockname(),getsockopt(), socket(), select(),

WSAAsyncSelect(), WSAEventSelect().

WSACreateEvent()

简述:创建一个新的事件对象。

#include <winsock2.h>

WSAEVENT WSAAPI WSACreateEvent( VOID );

返回值:

如果函数成功,则返回值即是事件对象的句柄。

如果函数失败,返回 WSA_INVALID_EVENT。应用程序可通过调用WSAGetLastError()函数获取进一步的错误信息。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSA_NOT_ENOUGH_MEMORY 无足够内存创建事件对象。

另请参阅: WSACloseEvent(), WSAEnumNetworkEvents(),WSAEventSelect(), WSAGetOverlappedResult(),WSARecv(), WSARecvFrom(), WSAResetEvent(),WSASend(), WSASendTo(), WSASetEvent(),WSAWaitForMultipleEvents().

WSADuplicateSocket()

简述:为一个共享套接口创建一个新的描述字。#include <winsock2.h>

SOCKET WSAAPI WSADuplicateSocket ( SOCKET s, WSATASK hTargetTask );

s: 指 定 本 地 套 接 口 描 述 字 。 hTargetTask:指定使用共享套接口的目标任务的句柄。

返回值:

若无错误发生,WSADuplicateSocket()返回新的套接口描述字。否则的话,将返回 INVALID_SOCKET 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEINVAL 参数中有非法值。

WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAEMFILE 无可用套接口描述字。WSAENOBUFS 无可用缓冲区空间,套接口未创建。WSAENOTSOCK 描述字不是一个套接口。

另请参阅:

WSAEnumNetworkEvents()

简述:检测所指定套接口上网络事件的发生。#include <winsock2.h>

int WSAAPI WSAEnumNetworkEvents ( SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS

lpNetworkEvents, LPINT lpiCount);

s: 标 识 套 接 口 的 描 述 字 。 hEventObject:(可选)句柄,用于标识需要复位的相应事件对象。lpNetworkEvents:一个 WSANETWORKEVENTS 结构的数组,每一个元素记录了一个网络事件和相应的错误代码。 lpiCount:数组中的元素数目。在返回时,本参数表示数组中的实际元素数目; 如果返回值是 WSAENOBUFS,则表示为获取所有网络事件所需的元素数目。

返回值:

如果操作成功则返回 0。否则的话,将返回 INVALID_SOCKET 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEINVAL 参数中有非法值。

WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAENOBUFS 所提供的缓冲区太小。另请参阅: WSAEventSelect()

WSAEnumProtocols()

简述:获取现有传送协议的相关信息。#include <winsock2.h>

int WSAAPI WSAEnumProtocols ( LPDWORD lpdwProtocols, LPVOID lpProtocolBuffer, LPDWORD lpdwBufferLength);

lpdwProtocols:一个以 NULL 结尾的协议标识号数组。本参数可选;如果lpdwProtocols 为 NULL,则返回所有可用协议的信息,否则的话只返回数组中所开列的协议信息。

lpProtocolBuffer:一个用 PROTOCOL_INFO 结构填充的缓冲区。参见下文中对PROTOCOL_INFO 结构的具体描述。

lpdwBufferLength:输入时,存有传递给 WSAEnumProtocols()函数的lpProtocolBuffer 缓冲区长度。输出时,表示为获取所有信息需传递给WSAEnumProtocols()函数的缓冲区长度。本函数不能重复调用;传入的缓冲区必须足够大以能存放所有的元素。这个规定降低了该函数的复杂度。由于一个机器上装载的协议数目往往是很小的,所以并不会产生问题。

返回值:

若无错误发生,WSAEnumProtocols()返回协议的数目。否则的话,将返回INVALID_SOCKET 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEINPROGRESS 一个阻塞 WinSock 调用正在进行。WSAEINVAL 参数中有非法值。

WSAENOBUFS 缓冲区太小,无法保存所有 PROTOCOL_INFO 结构及其相关信息。传入的缓冲区大小至少应等于 lpdwBufferLength 中返回的值。

WSAEventSelect()

简述:确定与所提供的 FD_XXX 网络事件集合相关的一个事件对象。#include <winsock2.h>

int WSAAPI WSAEventSelect ( SOCKET s, WSAEVENT hEventObject, long lNetworkEvents );

s: 一 个 标 识 套 接 口 的 描 述 字 。 hEventObject:一个句柄,用于标识与所提供的 FD_XXX 网络事件集合相关的一个事件对象。

lNetworkEvents:一个屏蔽位,用于指定感兴趣的 FD_XXX 网络事件组合。

返回值:

如果应用程序指定的网络事件及其相应的事件对象成功设置,则返回 0。否则的话,将返回 INVALID_SOCKET 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

在使用 select()和 WSAAsyncSelect()函数时,WSAEventSelect()常用来决定何时进行数据传送操作(如 send()或 recv()),并期望能立即成功。但是一个稳定的应用程序应该做好这样的准备,即事件对象被设置,并且一个 WinSock 调用以 WSAEWOULDBLOCK 立即返回 。举例来说,有可能发生下述操作序列:

  1. 套接口 s 上到达数据;WinSock 设置了 WSAEventSelect 事件对象。

  2. 应用程序进行其他操作。

  3. 在进行操作时,应用程序调用了 ioctlsocket(s,

    FIONREAD...)并发现有数据可读。

  4. 应用程序调用一个 recv(s,...)来读取数据。

  5. 最后应用程序等待

    WSAEventSelect()所指定的数据对象,该数据对象指出数据可读。

  6. 应用程序调用 recv(s,...),但以 WSAEWOULDBLOCK 错误失败。

其他的操作序列也是可能的。

成功地记录了网络事件的发生(通过设置内部网络事件记录的相应位),并且将相应的事件对象设置了信号后,不会对该网络事件作进一步的操作,直到应用程序调用了相应的函数显式地重新允许该网络事件及相应事件对象的信号。

网络事件 重新允许函数FD_READ recv() 或 recvfrom()

FD_WRITE send() 或 sendto()

FD_OOB recv()

FD_ACCEPT accept() 或 WSAAccept(),直到返回的错误代码为WSATRY_AGAIN,指明条件函数返回 CF_DEFER。

FD_CONNECT NONE FD_CLOSE NONE

FD_QOS 用 SIO_GET_QOS 命令调用 WSAIoctl()。FD_GROUP_QOS 用 SIO_GET_GROUP_QOS 命令调用 WSAIoctl()。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEINVAL 参数中有非法值,或者指定的套接口处于非法状态。WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAENOTSOCK 描述字不是一个套接口。

另请参阅:

WSACloseEvent() ,WSACreateEvent(),WSAEnumNetworkEvents(),WSAGetOverla ppedResult(),WSAWaitForMultipleEvents().

WSAGetOverlappedResult()

简述:返回指定套接口上一个重叠操作的结果。#include <winsock2.h>

BOOL WSAAPI WSAGetOverlappedResult( SOCKET s, LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer, BOOL fWait, LPDWORD lpdwFlags );

s:标识套接口。这就是调用重叠操作(WSARecv()、 WSARecvFrom()、WSASend()、WSASendTo() 或 WSAIoctl())时指定的那个套接口。lpOverlapped:指向调用重叠操作时指定的 WSAOVERLAPPED 结构。lpcbTransfer:指向一个 32 位变量,该变量用于存放一个发送或接收操作实际传 送 的 字 节 数 , 或 WSAIoctl() 传 送 的 字 节 数 。fWait:指定函数是否等待挂起的重叠操作结束。若为真 TRUE 则函数在操作完成后才返回。若为假 FALSE 且函数挂起,则函数返回 FALSE,WSAGetLastError() 函数返回 WSA_IO_INCOMPLETE。

lpdwFlags:指向一个 32 位变量,该变量存放完成状态的附加标志位。如果重叠操作为 WSARecv()或 WSARecvFrom(),则本参数包含lpFlags 参数所需的结果。

返回值:

如果函数成功,则返回值为真TRUE。它意味着重叠操作已经完成,lpcbTransfer所指向的值已经被刷新。应用程序可调用 WSAGetLastError()来获取重叠操作的错误信息。

如果函数失败,则返回值为假 FALSE。它意味着要么重叠操作未完成,要么由于一个或多个参数的错误导致无法决定完成状态。失败时,lpcbTransfer 指向的值不会被刷新。应用程序可用 WSAGetLastError()来获取失败的原因。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAENOTSOCK 描述字不是一个套接口。

WSA_INVALID_HANDLE WSAOVERLAPPED 结构的hEvent 域未包含一个有效的事件对象句柄。

WSA_INVALID_PARAMETER 有不可接受的参数。WSA_IO_INCOMPLETE fWait 假 FALSE 且输入/输出操作尚未完成。

另请参阅: WSACreateEvent(), WSAWaitForMultipleEvents(),WSARecv(), WSARecvFrom(), WSASend(), WSASendTo(),WSAConnect(), WSAAccept(), WSAIoctl().

WSAGetQoSByName()

简述:根据一个模板初始化 QOS。

#include <winsock2.h>

BOOL WSAAPI WSAGetQOSByName( SOCKET s, LPWSABUF

lpQOSName, LPQOS lpQOS);

s:一个标识套接口的描述字。lpQOSName:指定 QOS 模板的名字。lpQOS:指向待填充 QOS 结构的指针。

返回值:

如果函数成功,返回真 TRUE。如果函数失败,返回假 FALSE。可调用WSAGetLastError()来获取进一步的错误信息。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAENOTSOCK 描述字不是一个套接口。

WSAEFAULT lpQOS 参数不是用户地址空间的一个有效部分,或 lpQOS 的缓冲区太小。

WSA_INVAL 所指定的 QOS 模板名字非法。

另请参阅: WSAConnect(), WSAAccept(), getsockopt().

WSAHtonl()

简述:将一个以主机字节顺序表示的无符号长整形数转换为网络字节顺序。

#include <winsock2.h>

u_long WSAAPI WSAHtonl ( SOCKET s, u_long hostlong );

s:一个标识套接口的描述字。 hostlong:一个用主机字节顺序表示的 32 位数。

返回值:WSAHtonl()返回以网络字节顺序表示的值。错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。

WSAENETDOWN 网络子系统失效。

WSAENOTSOCK 描述字不是一个套接口。

另请参阅: htonl(), htons(), ntohs(), ntohl(), WSAHtons(),WSANtohl(), WSANtohs().

WSAHtons()

简述:将一个以主机字节顺序表示的无符号短整形数转换为网络字节顺序。#include <winsock2.h>

u_short WSAAPI WSAHtons (SOCKET sr, u_short hostshort );

s:一个标识套接口的描述字。 hostshort:一个以主机字节顺序表示的 16 位数。

返回值:WSAHtons()返回以网络字节顺序表示的值。错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。

WSAENETDOWN 网络子系统失效。WSAENOTSOCK 描述字不是一个套接口。

另请参阅: htonl(), htons(), ntohs(), ntohl(), WSAHtonl(),WSANtohl(), WSANtohs().

WSAIoctl()

简述:控制一个套接口的模式。

#include <winsock2.h>

int WSAAPI WSAIoctl(SOCKET s, DWORD

dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE

lpCompletionRoutine);

s: 一 个 套 接 口 的 句 柄 。 dwIoControlCode: 将 进 行 的 操 作 的 控 制 代 码 。 lpvInBuffer: 输 入 缓 冲 区 的 地 址 。 cbInBuffer: 输 入 缓 冲 区 的 大 小 。 lpvOutBuffer: 输 出 缓 冲 区 的 地 址 。 cbOutBuffer: 输 出 缓 冲 区 的 大 小 。 lpcbBytesReturned:输出实际字节数的地址。lpOverlapped:WSAOVERLAPPED 结构的地址。lpCompletionRoutine:一个指向操作结束后调用的例程指针。

返回值:

调用成功后,WSAIoctl ()函数返回 0。否则的话,将返回 INVALID_SOCKET 错误, 应用程序可通过 WSAGetLastError()来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEINVAL cmd 不是一个合法的命令;或者一个输入参数非法;或者命令对于该种类型的套接口不适用。

WSAEINPROGRESS 在一个回调函数运行时调用了该函数。WSAENOTSOCK 描述字不是一个套接口。

WSAEOPNOTSUPP 指定的 ioctl 命令无法实现,例如在 SIO_SET_QOS 或SIO_SET_GROUP_QOS 中指定的流描述无法实现。

WSA_IO_PENDING 一个重叠操作被成功启动,过后将报告完成情况。WSAEWOULDBLOCK 套接口标志为非阻塞,且所需操作将产生阻塞。

另请参阅: socket(), ioctlsocket(), WSASocket(),setsockopt(), getsockopt().

WSAJoinLeaf()

简述:将一个叶节点加入一个多点会晤,交换连接数据,根据提供的流描述确定所需的服务质量。

#include <winsock2.h>

SOCKET WSAAPI WSAJoinLeaf ( SOCKET s, const struct sockaddr FAR * name, int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData,

LPQOS lpSQOS, LPQOS lpGQOS, int iFlags );

s:标识一个多点套接口的描述字。name:将与套接口连接的远端名字。namelen:名字长度。

lpCallerData:一个指针,指向多点会晤创建时传送给远端的用户数据。lpCalleeData:一个指针,指向多点会晤创建时从远端传送回来的用户数据。lpSQOS:一个指向套接口 s 的流描述的指针,每个方向一个。lpGQOS:一个指向套接口组(如果存在)流描述的指针。 iFlags:标志位,用于指定套接口作为发送者。接收者或身兼二者。

返回值:若无错误发生,WSAJoinLeaf()返回新创建的多点套接口的描述字。否则的话,将返回 INVALID_SOCKET 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。

WSAENETDOWN 网络子系统失效。WSAEADDRINUSE 指定的地址已经在使用中。

WSAEINTR 通过 WSACancelBlockingCall()函数取消(阻塞)调用。WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAEALREADY 在指定的套接口上正在运行一个非阻塞的WSAJoinLeaf() 调用。

WSAEADDRNOTAVAIL 本地主机无法获得指定的地址。

WSAEAFNOSUPPORT 所指定地址族中的地址无法与本套接口一起使用。WSAECONNREFUSED 加入试图被强制拒绝。

WSAEFAULT name 或 namelen 参数不是用户地址空间的一个有效部分;namelen 参数太小;lpCalleeData、 lpSQOS 和 lpGQOS 的缓冲区太小; lpCallerData 缓冲区太大。

WSAEINVAL 套接口已与一个地址捆绑。

WSAEINVAL 套接口未与一个地址捆绑。WSAEISCONN 套接口已是多点会晤的一个成员。WSAENETUNREACH 当前无法从本主机联系网络。WSAENOBUFS 无可用缓冲区空间。套接口无法加入。WSAENOTSOCK 描述字不是一个套接口。

WSAEOPNOTSUPP lpSQOS 和 lpGQOS 中所指定的流描述无法满足。WSAEPROTONOSUPPORT 服务提供者不支持 lpCallerData 参数。WSAETIMEDOUT 加入试图超时,未建立多点会晤。

WSAEWOULDBLOCK 套接口被标志为非阻塞,但多点会晤加入操作无法立即完成。当用 select()选为读连接后,可使用 select()对套接口进行操作。

另请参阅: accept(), bind(), select(), WSAAccept(),WSAAsyncSelect(), WSAEventSelect(), WSASocket().

WSANtohl()

简述:将一个以网络字节顺序表示的无符号长整形数转换为主机字节顺序。#include <winsock2.h>

u_long WSAAPI WSANtohl ( SOCKET s, u_long netlong

);

s:一个标识套接口的描述字。 netlong:一个以网络字节顺序表示的 32 位数。

返回值:WSANtohl()返回一个以主机字节顺序表示的值。错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。

WSAENETDOWN 网络子系统失效。

WSAENOTSOCK 描述字不是一个套接口。

另请参阅: ntohl(), htonl(), htons(), ntohs(), WSAHtonl(),WSAHtons(), WSANtohs().

WSANtohs()

简述:将一个以网络字节顺序表示的无符号短整形数转换为主机字节顺序。#include <winsock2.h>

u_short WSAAPI WSANtohs (SOCKET s, u_short netshort );

s:一个标识套接口的描述字。 netshort:一个以网络字节顺序标识的 16 位数。

返回值:WSANtohs()返回以主机字节顺序表示的值。错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。

WSAENETDOWN 网络子系统失效。

WSAENOTSOCK 描述字不是一个套接口。

另请参阅: htonl(), htons(), ntohs(), ntohl(), WSAHtonl(),WSAHtons(), WSANtohl().

WSARecv()

简述:从一个套接口接收数据。

#include <winsock2.h>

int WSAAPI WSARecv ( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPINT lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE

lpCompletionRoutine );

s:一个标识已连接套接口的描述字。

lpBuffers:一个指向 WSABUF 结构数组的指针。每一个 WSABUF 结构包含一个缓冲区的指针和缓冲区的长度。

dwBufferCount:lpBuffers 数组中 WSABUF 结构的数目。lpNumberOfBytesRecvd:如果接收操作立即结束,一个指向本调用所接收的字节数的指针。

lpFlags:一个指向标志位的指针。

lpOverlapped:一个指向 WSAOVERLAPPED 结构的指针(对于非重叠套接口则忽略 ) 。 lpCompletionRoutine:一个指向接收操作结束后调用的例程的指针(对于非重叠套接口则忽略)。

返回值:

若无错误发生且接收操作立即完成,则 WSARecv()函数返回所接收的字节数。如果连接结束,则返回 0。请注意在这种情况下完成指示(启动指定的完成例程或设置一个事件对象)将早已发生。否则的话,将返回 SOCKET_ERROR 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。错误代码WSA_IO_PENDING 表示重叠操作成功启动,过后将有完成指示。任何其他的错误表示重叠操作未能成功地启动,以后也不会有完成指示。

如果设置了 MSG_INTERRUPT 标志,则返回值的含义变化。零表示成功,具体含义同上。否则的话,返回值直接包含如下所示的错误代码。由于中断环境中无法调用 WSAGetLastError(),故是必需的。请注意仅适用于 Win16 环境,仅适用于PROTOCOL_INFO 结构中设置了 XP1_INTERRUPT 位的协议。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAENOTCONN 套接口未连接。

WSAEINTR 通过 WSACancelBlockingCall()函数取消(阻塞)调用。WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAENETRESET 由于远端的复位造成连接的中止。WSAENOTSOCK 描述字不是一个套接口。

WSAEOPNOTSUPP 设置了 MSG_OOB,但是该套接口不是诸如 SOCK_STREAM 流类型的,与套接口相关的通讯域不支持带外数据,或者套接口是单向的,只支持发送操作。

WSAESHUTDOWN 套接口已经关闭;一个套接口以 SD_RECEIVE 或SD_BOTH 的 how 参数 shutdown()后,无法进行 WSARecv()调用。

WSAEWOULDBLOCK 重叠套接口:太多重叠的输入/输出请求。非重叠套接口:套接口被标志为非阻塞,但是操作不能立即完成。

WSAEINVAL 套接口未用 bind()捆绑,或者套接口未用重叠标志创建。

WSAECONNABORTED 由于超时或其他错误导致虚电路中止。WSAECONNRESET 虚电路被远端复位。

WSAEDISCON 远端优雅的结束了连接。

WSA_IO_PENDING 成功启动一个重叠操作,过后将有完成指示。

另请参阅: WSACloseEvent(),WSACreateEvent(),WSAGetOverlappedResult(), WSASocket(),WSAWaitForMultipleEvents()

WSARecvDisconnect()

简述:中止一个套接口上的接收操作;若套接口为面向连接的,则检索中止连接数据。

#include <winsock2.h>

int WSAAPI WSARecvDisconnect ( SOCKET s, LPWSABUF lpInboundDisconnectData );

s: 一 个 标 识 套 接 口 的 描 述 字 。 lpInboundDisconnectData:一个指向前来的中止连接数据的中止。

返回值:若无错误发生,WSARecvDisconnect()返回 0。否则的话,返回SOCKET_ERROR,应用程序可通过调用 WSAGetLastError()函数来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEFAULT lpInboundDisconnectData 参数所提供的缓冲区太小。WSAENOPROTOOPT 指定地址族不支持中止连接数据。

WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAENOTCONN 套接口未连接(仅适用于面向连接的套接口)。WSAENOTSOCK 描述字不是一个套接口。

另请参阅: connect(), socket().

WSARecvFrom()

简述:接收一个数据报并保存源地址。#include <winsock2.h>1

int WSAAPI WSARecvFrom ( SOCKET s, LPWSABUF

lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPINT lpFlags, LPVOID lpFrom, LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE

lpCompletionRoutine );

s:一个标识套接口的描述字。

lpBuffers:一个指向 WSABUF 结构数组的指针。每个 WSABUF 结构包含缓冲区的指针和缓冲区的大小。

dwBufferCount:lpBuffers 数组中 WSABUF 结构的数目。lpNumberOfBytesRecvd:如果接收操作立即完成,则为一个指向所接收数据字节数的指针。

lpFlags:一个指向标志位的指针。 lpFrom:(可选)指针,指向重叠操作完成后存放源地址的缓冲区。

lpFromlen:指向 from 缓冲区大小的指针,仅当指定了 lpFrom 才需要。lpOverlapped:指向 WSAOVERLAPPED 结构的指针(对于非重叠套接口则忽略)。lpCompletionRoutine:一个指向接收操作完成后调用的完成例程的指针。(对于非重叠套接口则忽略)。

返回值:

若无错误发生且接收操作立即完成,则 WSARecvFrom()函数返回所接收的字节数。如果连接结束,则返回 0。请注意在这种情况下完成指示(启动指定的完成例程或设置一个事件对象)将早已发生。否则的话,将返回 SOCKET_ERROR 错误, 应用程序可通过 WSAGetLastError()来获取相应的错误代码。错误代码WSA_IO_PENDING 表示重叠操作成功启动,过后将有完成指示。任何其他的错误表示重叠操作未能成功地启动,以后也不会有完成指示。

如果设置了 MSG_INTERRUPT 标志,则返回值的含义变化。零表示成功,具体含义同上。否则的话,返回值直接包含如下所示的错误代码。由于中断环境中无法调用 WSAGetLastError(),故是必需的。请注意仅适用于 Win16 环境,仅适用于PROTOCOL_INFO 结构中设置了 XP1_INTERRUPT 位的协议。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEFAULT lpFromlen 参数非法;lpFrom 缓冲区太小,无法容纳远端地址。

WSAEINTR 通过 WSACancelBlockingCall()函数取消(阻塞)调用。WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAEINVAL 套接口未用 bind()捆绑,或者套接口未用重叠标志创建。

WSAENETRESET 由于远端的复位造成连接的中止。

WSAENOTCONN 套接口未连接。(仅适用于面向连接的套接口)。WSAENOTSOCK 描述字不是一个套接口。

WSAEOPNOTSUPP 设置了 MSG_OOB,但是该套接口不是诸如 SOCK_STREAM 流类型的,与套接口相关的通讯域不支持带外数据,或者套接口是单向的,只支持发送操作。

WSAESHUTDOWN 套接口已经关闭;一个套接口以 SD_RECEIVE 或SD_BOTH 的 how 参数 shutdown()后,无法进行 WSARecvFrom()调用。

WSAEWOULDBLOCK 重叠套接口:太多重叠的输入/输出请求。非重叠套接口:套接口被标志为非阻塞,但是操作不能立即完成。

WSAEMSGSIZE 消息太大无法全部装入指定的缓冲区,故被修剪。

WSAECONNABORTED 由于超时或其他错误导致虚电路中止。WSAECONNRESET 虚电路被远端复位。

WSAEDISCON 远端优雅地中止了连接。

WSA_IO_PENDING 成功启动一个重叠操作,过后将有完成指示。

另请参阅: WSACloseEvent(),WSACreateEvent(),WSAGetOverlappedResult(), WSASocket(),WSAWaitForMultipleEvents()

WSAResetEvent()

简述:将指定的事件对象状态清除为未置信号。#include <winsock2.h>

BOOL WSAAPI WSAResetEvent( WSAEVENT hEvent ); hEvent:标识一个开放的事件对象句柄。

返回值:

如果函数成功,返回真 TRUE。如果函数失败,返回假 FALSE。可调用WSAGetLastError()来获取进一步的错误信息。

错误代码:

WSA_INVALID_HANDLE hEvent 不是一个合法的事件对象句柄。

另请参阅: WSACreateEvent(), WSASetEvent(), WSACloseEvent().

WSASend()

简述:在一个已连接的套接口上发送数据。#include <winsock2.h>

int WSAAPI WSASend ( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, int iFlags, LPWSAOVERLAPPED lpOverlapped,

LPWSAOVERLAPPED_COMPLETION_ROUTINE

lpCompletionRoutine );

s:标识一个已连接套接口的描述字。

lpBuffers:一个指向 WSABUF 结构数组的指针。每个 WSABUF 结构包含缓冲区的指针和缓冲区的大小。

dwBufferCount:lpBuffers 数组中 WSABUF 结构的数目。lpNumberOfBytesSent:如果发送操作立即完成,则为一个指向所发送数据字节数的指针。

iFlags:标志位。

lpOverlapped:指向 WSAOVERLAPPED 结构的指针(对于非重叠套接口则忽略)。lpCompletionRoutine:一个指向发送操作完成后调用的完成例程的指针。(对于非重叠套接口则忽略)。

返回值:

若无错误发生且发送操作立即完成,则 WSASend()函数返回所发送的字节数。

(注意该数目可能小于 len 参数所指定的值)。如果连接结束,则返回 0。请注意在这种情况下完成指示(启动指定的完成例程或设置一个事件对象)将早已发生。否则的话,将返回 SOCKET_ERROR 错误,应用程序可通过 WSAGetLastError() 来获取相应的错误代码。错误代码 WSA_IO_PENDING 表示重叠操作成功启动,过后将有完成指示。任何其他的错误表示重叠操作未能成功地启动,以后也不会有完成指示。

如果设置了 MSG_INTERRUPT 标志,则返回值的含义变化。零表示成功,具体含义同上。否则的话,返回值直接包含如下所示的错误代码。由于中断环境中无法调用 WSAGetLastError(),故是必需的。请注意仅适用于 Win16 环境,仅适用于PROTOCOL_INFO 结构中设置了 XP1_INTERRUPT 位的协议。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEACCES 请求地址为广播地址,但相应标志位没有设置。WSAEINTR 通过 WSACancelBlockingCall()函数取消(阻塞)调用。WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAEFAULT lpBuffer 参数并不是用户地址空间的一个有效部分。WSAENETRESET 由于远端复位造成连接的中止。

WSAENOBUFS WinSock 提供者报告一个缓冲区死锁。WSAENOTCONN 套接口未连接。

WSAENOTSOCK 描述字不是一个套接口。

WSAEOPNOTSUPP 设置了 MSG_OOB,但是该套接口不是诸如 SOCK_STREAM 流类型的,与套接口相关的通讯域不支持带外数据,或者套接口是单向的,只支持接收操作。

WSAESHUTDOWN 套接口已经关闭;一个套接口以 SD_SEND 或 SD _BOTH 的 how 参数 shutdown()后,无法进行 WSASend()调用。

WSAEWOULDBLOCK 太多的重叠输入/输出操作。

WSAEMSGSIZE 套接口是面向消息的,但是消息大于底层传送的最大值。

WSAEINVAL 套接口未用 bind()捆绑,或者套接口未用重叠标志位创建。

WSAECONNABORTED 由于超时或其他错误导致虚电路中止。WSAECONNRESET 虚电路被远端复位。

WSA_IO_PENDING 成功启动重叠操作,过后将有完成指示。

另请参阅: WSACloseEvent(),WSACreateEvent(),WSAGetOverlappedResult(), WSASocket(),WSAWaitForMultipleEvents()

WSASendDisconnect()

简述:启动套接口连接的中止操作。

#include <winsock2.h>

int WSAAPI WSASendDisconnect ( SOCKET s, LPWSABUF lpOutboundDisconnectData );

s: 一 个 标 识 套 接 口 的 描 述 字 。 lpOutboundDisconnectData:指向发出的中止连接数据的指针。

返回值:若无错误发生,WSASendDisconnect()返回 0。否则的话,将返回SOCKET_ERROR 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAENOPROTOOPT lpOutboundDisconnectData 参数非 NULL,复位提供者不支持中止连接数据。

WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAENOTCONN 套接口未连接(仅适用于面向连接的套接口)。WSAENOTSOCK 描述字不是一个套接口。

另请参阅: connect(), socket().

WSASendTo()

简述:向指定地址发送数据,可能的话使用重叠输入/输出操作。#include <winsock2.h>

int WSAAPI WSASendTo ( SOCKET s, LPWSABUF

lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, int iFlags, LPVOID lpTo, int iToLen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE

lpCompletionRoutine );

s:用于标识一个已连接的套接口,该套接口以 WSA_FLAG_OVERLAPPED 标志调用WSASocket()创建。

lpBuffers:一个指向 WSABUF 结构数组的指针。每个 WSABUF 结构包含缓冲区的指针和缓冲区的大小。

dwBufferCount:lpBuffers 数组中 WSABUF 结构的数目。lpNumberOfBytesSent:如果发送操作立即完成,则为一个指向所发送数据字节数的指针。

iFlags: 标 志 位 。 lpTo:(可选)指针,指向目标套接口的地址。lpTolen:lpTo 中地址的大小。

lpOverlapped:指向 WSAOVERLAPPED 结构的指针(对于非重叠套接口则忽略)。lpCompletionRoutine:一个指向发送操作完成后调用的完成例程的指针。(对于非重叠套接口则忽略)。

返回值:

若无错误发生且发送操作立即完成,则 WSASendTo()函数返回所发送的字节数

(请注意它可能小于 len 所指定的值)。请注意在这种情况下完成指示(启动指定的完成例程或设置一个事件对象)将早已发生。否则的话,将返回SOCKET_ERROR 错误,应用程序可通过 WSAGetLastError()来获取相应的错误代码。错误代码WSA_IO_PENDING 表示重叠操作成功启动,过后将有完成指示。任何其他的错误表示重叠操作未能成功地启动,以后也不会有完成指示。

如果设置了 MSG_INTERRUPT 标志,则返回值的含义变化。零表示成功,具体含义同上。否则的话,返回值直接包含如下所示的错误代码。由于中断环境中无法调用 WSAGetLastError(),故是必需的。请注意仅适用于 Win16 环境,仅适用于PROTOCOL_INFO 结构中设置了 XP1_INTERRUPT 位的协议。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEACCES 请求的地址为广播地址,但未设置相应的标志位。WSAEINTR 通过 WSACancelBlockingCall()函数取消(阻塞)调用。WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAEFAULT lpBuffer 或 lpTo 参数不是用户地址空间的一部分;或者 lpTo 参数太小(小于 sockaddr 结构的大小)。

WSAENETRESET 远端主机复位造成连接的中止。WSAENOBUFS WinSock 提供者报告了一个缓冲区死锁。

WSAENOTCONN 套接口未连接(仅适用于面向连接的套接口)。WSAENOTSOCK 描述字不是一个套接口。

WSAEOPNOTSUPP 设置了 MSG_OOB,但是该套接口不是诸如 SOCK_STREAM 流类型的,与套接口相关的通讯域不支持带外数据,或者套接口是单向的,只支持接收操作。

WSAESHUTDOWN 套接口已经关闭;一个套接口以 SD_SEND 或 SD _BOTH 的 how 参数 shutdown()后,无法进行 WSASendTo()调用。

WSAEWOULDBLOCK 太多重叠的输入/输出请求。

WSAEMSGSIZE 套接口是面向消息的,且消息大于底层传送所支持的最大长度。

WSAEINVAL 套接口未用 bind()捆绑,或者套接口未用重叠标志位创建。

WSAECONNABORTED 由于超时或其他错误导致虚电路中止。WSAECONNRESET 虚 电 路 被 远 端 复 位 。 WSAEADDRNOTAVAIL 本地主机无法获取所指定的地址。

WSAEAFNOSUPPORT 指定地址族中的地址无法与本套接口一起使用。WSAEDESTADDRREQ 需要目的地地址。

WSAENETUNREACH 当 前 无 法 从 本 主 机 联 系 网 络 。 WSA_IO_PENDING 成功启动一个重叠操作,过后将有完成指示。

另请参阅: WSACloseEvent(),WSACreateEvent(),WSAGetOverlappedResult(), WSASocket(),WSAWaitForMultipleEvents()

WSASetEvent()

简述:将指定的事件对象状态设置为有信号。#include <winsock2.h>

BOOL WSAAPI WSASetEvent( WSAEVENT hEvent );

hEvent:标识一个开放的事件对象句柄。返回值:

如果函数成功,返回真 TRUE。

如果函数失败,返回假 FALSE。可通过调用 WSAGetLastError()来获取进一步的错误信息。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSA_INVALID_HANDLE hEvent 不是一个合法的事件对象句柄。

另请参阅: WSACreateEvent(), WSAResetEvent(),WSACloseEvent().

WSASocket()

简述:创建一个与指定传送服务提供者捆绑的套接口,可选地创建和/或加入一个套接口组。

#include <winsock2.h>

SOCKET WSAAPI WSASocket ( int af, int type, int protocol, LPPROTOCOL_INFO lpProtocolInfo, Group g, int iFlags);

af:地址族描述。目前仅支持 PF_INET 格式,亦即 ARPA Internet 地址格式。type: 新 套 接 口 的 类 型 描 述 。 protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为 0。lpProtocolInfo:一个指向 PROTOCOL_INFO 结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。g:套接口组的描述字。

iFlags:套接口属性描述。

返回值:

若无错误发生,WSASocket()返回新套接口的描述字。否则的话,返回INVALID_SOCKET,应用程序可定调用 WSAGetLastError()来获取相应的错误代码。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSAEAFNOSUPPORT 不支持指定的地址族。

WSAEINPROGRESS 一个阻塞的 WinSock 调用正在进行中,或者服务提供者仍在处理一个回调函数。(参见 B.3.6.6 节)

WSAEMFILE 无 可 用 的 套 接 口 描 述 字 。 WSAENOBUFS 无可用的缓冲区空间。套接口无法创建。WSAEPROTONOSUPPORT 不支持指定的协议。

WSAEPROTOTYPE 指定的协议对于本套接口类型错误。WSAESOCKTNOSUPPORT 本地址族不支持指定的套接口类型。WSAEINVAL g 参数非法。

另请参阅: accept(), bind(), connect(), getsockname(),getsockopt(), setsockopt(), listen(), recv(),recvfrom(), select(), send(), sendto(),shutdown(), ioctlsocket().

WSAWaitForMultipleEvents()

简述:只要指定事件对象中的一个或全部处于有信号状态,或者超时间隔到,则返回。

#include <winsock2.h>

DWORD WSAAPI WSAWaitForMultipleEvents( DWORD cEvents,

const WSAEVENT FAR * lphEvents, BOOL fWaitAll, DWORD dwTimeout,

BOOL fAlertable );

cEvents:指出 lphEvents 所指数组中事件对象句柄的数目。事件对象句柄的最大值为 WSA_MAXIMUM_WAIT_EVENTS。

lphEvents:指向一个事件对象句柄数组的指针。 fWaitAll:指定等待类型。若为真 TRUE,则当 lphEvents 数组中的所有事件对象同时有信号时,函数返回。若为假 FALSE,则当任意一个事件对象有信号时函数即返回。在后一种情况下,返回值指出是哪一个事件对象造成函数返回。dwTimeout:指定超时时间间隔(以毫秒计)。当超时间隔到,函数即返回,不论 fWaitAll 参数所指定的条件是否满足。如果 dwTimeout 为零,则函数测试指定的时间对象的状态,并立即返回。如果 dwTimeout 是 WSA_INFINITE,则函数的超时间隔永远不会到。

fAlertable:指定当系统将一个输入/输出完成例程放入队列以供执行时,函数是否返回。若为真 TRUE,则函数返回且执行完成例程。若为假 FALSE,函数不返回,不执行完成例程。请注意在 Win16 中忽略该参数。

返回值:

如果函数成功,返回值指出造成函数返回的事件对象。

如果函数失败,返回值为 WSA_WAIT_FAILED。可调用 WSAGetLastError()来获取进一步的错误信息。

错误代码:

WSANOTINITIALISED 在调用本 API 之前应成功调用 WSAStartup()。WSAENETDOWN 网络子系统失效。

WSA_NOT_ENOUGH_MEMORY 无足够内存完成该操作。

WSA_INVALID_HANDLE lphEvents 数组中的一个或多个值不是合法的事件对象句柄。

WSA_INVALID_PARAMETER cEvents 参数未包含合法的句柄数目。另请参阅: WSACreateEvent(), WSACloseEvent().