7 通信超时
通信超时是影响读写操作的另一个重要方面。如果操作所用时间大于超时值,则操作完成,ReadFile、WriteFile、GetOverlappedResule或者WaitForSingleObject不会返回错误代码,它们都指示操作成功完成。实际传输的字节数小于请求的字节数是操作超时的唯一指示。如果ReadFile返回TRUE,但是读取到的字节数小于请求的字节数,则操作超时了。如果重叠写操作超时,则重叠事件句柄受信,WaitForSingleObject返回WAIT_OBJECT_0;GetOverlappedResult返回TRUE,dwBytesTransferred指示超时前已经传输的字节数。下面的代码展示了如何处理这种情况:
BOOL WriteABuffer(char * lpBuf, DWORD dwToWrite)
{
OVERLAPPED osWrite = {0};
DWORD dwWritten;
DWORD dwRes;
BOOL fRes;
// Create this write operation's OVERLAPPED structure hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// Error creating overlapped event handle.
return FALSE;
// Issue write
if (!WriteFile(hComm, lpBuf, dwToWrite, &dwWritten, &osWrite)) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but it isn't delayed. Report error.
fRes = FALSE;
}
else
// Write is pending.
dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch(dwRes)
{
// Overlapped event has been signaled.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, FALSE))
fRes = FALSE;
else {
if (dwWritten != dwToWrite) {
// The write operation timed out. I now need to
// decide if I want to abort or retry. If I retry,
// I need to send only the bytes that weren't sent.
// If I want to abort, I would just set fRes to
// FALSE and return.
fRes = FALSE;
}
else
// Write operation completed successfully.
fRes = TRUE;
}
break;
default:
// An error has occurred in WaitForSingleObject. This usually
// indicates a problem with the overlapped event handle.
fRes = FALSE;
break;
}
}
}
else {
// WriteFile completed immediately.
if (dwWritten != dwToWrite) {
// The write operation timed out. I now need to
// decide if I want to abort or retry. If I retry,
// I need to send only the bytes that weren't sent.
// If I want to abort, then I would just set fRes to
// FALSE and return.
fRes = FALSE;
}
else
fRes = TRUE;
}
CloseHandle(osWrite.hEvent);
return fRes;
}
SetCommTimeouts 用以设置端口的通信超时值;GetCommTimeouts获取通信超时。下面是代码示例:
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 20;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.ReadTotalTimeoutConstant = 100;
timeouts.WriteTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hComm, &timeouts))
// Error setting time-outs.
注意 通信超时不同于同步函数中的超时值。比如说,WaitForSingleObject中的超时值指定了等待对象受信的时间限制,它不同于通信超时。
如果设置COMMTIMOUTS的各个成员为零,则不会发生超时。非重叠操作会阻塞直到请求的字节数传输完成:ReadFile会阻塞直到所有请求的字符到达端口;WriteFile会阻塞直到所有请求的字符被发送。重叠操作只有在所有字符已经传输,或者取消操作时才完成。只有操作完成时才发生下列条件:
- WaitForSingleObject always returns WAIT_TIMEOUT if a synchronization time-out is supplied. WaitForSingleObject will block forever if an INFINITE synchronization time-out is used.
- GetOverlappedResult always returns FALSE and GetLastError returns ERROR_IO_INCOMPLETE if called directly after the call to GetOverlappedResult.
Setting the members of the COMMTIMEOUTS structure in the following manner causes read operations to complete immediately without waiting for any new data to arrive:
COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(hComm, &timeouts)) // Error setting time-outs.
These settings are necessary when used with an event-based read described in the "Caveat" section earlier. In order for ReadFile to return 0 bytes read, the ReadIntervalTimeout member of the COMMTIMEOUTS structure is set to MAXDWORD, and the ReadTimeoutMultiplier and ReadTimeoutConstant are both set to zero.
An application must always specifically set communications time-outs when it uses a communications port. The behavior of read and write operations is affected by communications time-outs. When a port is initially open, it uses default time-outs supplied by the driver or time-outs left over from a previous communications application. If an application assumes that time-outs are set a certain way, while the time-outs are actually different, then read and write operations may never complete or may complete too often.