超时
通信资源的句柄具有一组关联的超时参数,这些参数会影响读写操作的行为。 超时可能会导致 ReadFile、ReadFileEx、WriteFile 或 WriteFileEx 操作在超时间隔过后结束,即使指定的字符数尚未读取或写入也是如此。 当读取或写入操作期间发生超时(即读取或写入函数的返回值指示成功)时,它不会被视为错误。 实际读取或写入的字节计数由 ReadFile 或 WriteFile 报告(或者,如果 I/O 作为重叠操作执行,则由 GetOverlappedResult 或 FileIOCompletionRoutine 函数报告)。
当应用程序打开通信资源时,系统将资源的超时值设置为上次使用资源时生效的值。 如果通信资源从未打开,系统将超时值设置为一些默认值。 在任一情况下,应用程序在打开资源后应始终确定当前超时值,然后显式设置它们以满足其要求。 若要确定通信资源的当前超时值,请使用 GetCommTimeouts 函数。 若要更改超时值,请使用 SetCommTimeouts 函数。
超时参数启用两种类型的超时。 当收到任意两个字符之间的时间超过指定的毫秒数时,将发生间隔超时。 在收到第一个字符时开始计时,并在收到每个新字符时重新启动。 当读取操作花费的总时间超过计算的毫秒数时,将发生总超时。 I/O 操作开始时,计时会立即开始。 写入操作仅支持总超时。 读取操作支持间隔和总超时,可以单独使用或组合使用。
读取或写入操作的总超时期限的时间(以毫秒为单位)可使用 GetCommTimeouts 或 SetCommTimeouts 函数中指定的 COMMTIMEOUTS 结构的乘数和常量值计算。 使用以下公式:
Timeout = (MULTIPLIER * number_of_bytes) + CONSTANT
使用乘数和常量可更改总超时期限,具体取决于所请求的数据量。 应用程序只能通过将乘数设置为零来使用常量,或者仅通过将常数设置为零来使用乘数。 如果常量和乘数均为零,则不使用总超时。
如果所有读取超时参数均为零,则不使用读取超时,并且读取操作在读取请求的字节数或发生错误之前不会完成。 同样,如果所有写入超时参数均为零,则在写入请求的字节数或发生错误之前,不会完成写入操作。
如果读取间隔超时参数是 MAXDWORD 值,并且两个读取总超时参数均为零,则读取操作在读取输入缓冲区中可用的字符后立即完成,即使为空也是如此。
间隔计时强制读取操作在接收时返回。 使用间隔超时的进程可以设置一个相当短的间隔参数,因此它可以快速响应一个或多个字符的小型隔离突发,但当在稳定流中收到数据时,它仍然可以使用单个调用收集大型字符缓冲区。
当某种流控制阻止传输或调用 SetCommBreak 函数以暂停字符传输时,写入操作的超时可能很有用。
下表根据为总计和间隔超时指定的值汇总了读取操作的行为。
总计 | 间隔 | 行为 |
---|---|---|
0 | 0 | 当缓冲区完全填充时返回。 不使用超时。 |
T | 0 | 当缓冲区完全填充或自操作开始以来 T 毫秒已过时返回。 |
0 | Y | 当缓冲区完全填充或 Y 毫秒在收到任意两个字符之间时返回。 在收到第一个字符之前,计时不会开始。 |
T | Y | 当缓冲区完全填充或发生任一类型的超时时返回。 |
备注
但是,该计时与控制物理设备的系统有关。 对于远程设备(如调制解调器),计时相对于连接到调制解调器的服务器系统。 不考虑任何网络传播延迟。 例如,客户端应用程序可以指定计算为 500 毫秒的总超时。 在服务器上运行 500 毫秒时,将超时错误返回到客户端。 如果网络传播延迟为 50 毫秒,客户端将不会收到超时通知,直到实际发生超时大约 50 毫秒。
备注
超时参数会影响通信设备上的重叠读取和写入操作的行为。 使用重叠的 I/O,ReadFile、WriteFile、ReadFileEx 或 WriteFileEx 函数可以在操作完成之前返回。 超时参数可以确定操作何时完成。