询问者
串口通讯用api函数,数据收发不全

问题
-
在应用中,采用异步的方式进行串口数据的收发,在silicon lab的usb转串口芯片上出现了,readfile返回值为true,但获取的 实际字节数与缓冲区可用字节数不等,由于范围为true,根据msdn的手册,就未执行GetOverlappedResult,通用通讯底层,在其他串口上未出现该现象,完整代码如下。请问导致该问题的原因是什么?
#pragma hdrstop
#include "SerialPortEx.h"
#include <stdio.h>
#include <string>
#include "MessageDefine.h"
#include "DebugFile.h"
#include "UserConfig.hpp"
using namespace std;
//---------------------------------------------------------------------------
#pragma package(smart_init)
__fastcall CSerialPortEx::CSerialPortEx(TComponent* AOwner, bool msgEnable)
:CAbstractDevice(AOwner, msgEnable)
{
m_hSerialPort = NULL;
if (m_overlappedRead.hEvent != NULL) //m_overlapped.hEvent 事件内核对象 对文件的读写请求
ResetEvent(m_overlappedRead.hEvent);
m_overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //overlapped 成员 hEvent必须设置TRUE 手动重置
if (m_overlappedWrite.hEvent != NULL) //m_overlapped.hEvent 事件内核对象 对文件的读写请求
ResetEvent(m_overlappedWrite.hEvent);
m_overlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //overlapped 成员 hEvent必须设置TRUE 手动重置
if (m_hShutdownEvent != NULL)
ResetEvent(m_hShutdownEvent);
m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //退出串口事件 手动重置
// initialize the event objects
m_hEventArray[0] = m_hShutdownEvent; // highest priority 最高优先级
m_hEventArray[1] = m_overlappedRead.hEvent;
// m_Critical作为是否要进临界区的标记, m_waitInterval 配置读的等待间隔
// m_waitInterval < 200 时,发生读取数据不全的概率较大
m_Critical = GetSerialInterVal(m_waitInterval);
}
__fastcall CSerialPortEx::~CSerialPortEx()
{
if(m_overlappedRead.hEvent)
{
ResetEvent(m_overlappedRead.hEvent);
m_overlappedRead.hEvent = NULL;
}
if(m_overlappedWrite.hEvent)
{
ResetEvent(m_overlappedWrite.hEvent);
m_overlappedWrite.hEvent = NULL;
}
if(m_hShutdownEvent)
{
ResetEvent(m_hShutdownEvent);
m_hShutdownEvent = NULL;
}
}
bool CSerialPortEx::IsOpen()
{
// return m_SerialPort.IsOpen();
if(m_hSerialPort == INVALID_HANDLE_VALUE)
return false;
else
return m_hSerialPort != NULL;
}
bool CSerialPortEx::Close()
{
BOOL res;
if(IsOpen())
{
SetEvent(m_hShutdownEvent);
Sleep(1);
res = CloseHandle(m_hSerialPort);
g_debugFile.AddText("关闭串口:"+IntToStr(m_nPort)+" !");
if(res)
m_hSerialPort = NULL;
return res;
}
else
return TRUE;
}
bool CSerialPortEx::Open()
{
try
{
if(IsOpen())
{
return TRUE;
}
if(initPort(this,m_nPort,m_nBaud,m_chParity,m_nDataBits,m_nStopsBits,
EV_RXCHAR | EV_CTS))
{
g_debugFile.AddText("打开串口:"+IntToStr(m_nPort)+" 成功!");
return true;
}
else
{
g_debugFile.AddText("打开串口:"+IntToStr(m_nPort)+" 失败!");
return false;
}
}
catch(char* err)
{
g_debugFile.AddText("打开串口:"+IntToStr(m_nPort)+" 异常!");
return false;
}
}
void CSerialPortEx::SetDeviceProperties(const char* szProperties)
{
string strProperties(szProperties);
int nIndex = strProperties.find_first_of(',');
string strPort = strProperties.substr(0,nIndex);
strProperties = strProperties.substr(nIndex + 1);
nIndex = strProperties.find_first_of(',');
string strBaud = strProperties.substr(0,nIndex);
strProperties = strProperties.substr(nIndex + 1);
nIndex = strProperties.find_first_of(',');
string strParity = strProperties.substr(0,nIndex);
strProperties = strProperties.substr(nIndex + 1);
nIndex = strProperties.find_first_of(',');
string strDataBits = strProperties.substr(0,nIndex);
strProperties = strProperties.substr(nIndex + 1);
nIndex = strProperties.find_first_of(',');
string strStopBits = strProperties.substr(0,nIndex);
strProperties = strProperties.substr(nIndex + 1);
nIndex = strProperties.find_first_of(',');
string strSndBufferSize = strProperties.substr(0,nIndex);
strProperties = strProperties.substr(nIndex + 1);
nIndex = strProperties.find_first_of(',');
string strRcvBufferSize = strProperties.substr(0,nIndex);
strProperties = strProperties.substr(nIndex + 1);
m_nPort = atoi(strPort.c_str());
m_nBaud = atoi(strBaud.c_str());
m_chParity = strParity[0];
m_nDataBits = atoi(strDataBits.c_str());
m_nStopsBits = atoi(strStopBits.c_str());
m_nSndBufferSize = atoi(strSndBufferSize.c_str());
m_nRcvBufferSize = atoi(strRcvBufferSize.c_str());
if(IsOpen())
{
Close();
Sleep(100);
Open();
}
}
void CSerialPortEx::Send(const BYTE* pBuffer, const DWORD nSize)
{
if(m_Critical)
{
EnterCriticalSection(m_pCriticalSection_Snd);
m_dwSendSize = nSize;
memset(m_szSendBuffer, 0, m_dwSendSize);
memcpy(m_szSendBuffer,pBuffer,m_dwSendSize);
send();
LeaveCriticalSection(m_pCriticalSection_Snd);
}
else
{
m_dwSendSize = nSize;
memset(m_szSendBuffer, 0, m_dwSendSize);
memcpy(m_szSendBuffer,pBuffer,m_dwSendSize);
send();
}
}
void CSerialPortEx::Receive(BYTE*& pBuffer, int& nSize)
{
}
//---------------------------------------------------------------------------
//--打开串口
//--------------------------------------------------------------------------
BOOL CSerialPortEx::initPort(HANDLE hMsgRcver, unsigned long dwPortnr, unsigned long dwBaud,
char cParity, unsigned long dwDatabits, unsigned long dwStopbits,
unsigned long dwCommEvents)
{
char szPort[20] = {0};
char szBaud[100] = {0};
sprintf(szPort, "\\\\.\\COM%d", dwPortnr);
sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", dwBaud, cParity,
dwDatabits, dwStopbits);
ResetEvent(m_hShutdownEvent);
ResetEvent(m_overlappedRead.hEvent);
ResetEvent(m_overlappedWrite.hEvent);
m_hSerialPort = CreateFile(szPort, // communication port string (COMX)
GENERIC_READ | GENERIC_WRITE, // read/write types
0, // comm devices must be opened with exclusive access
NULL, // no security attributes
OPEN_EXISTING, // comm devices must use OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, // Async I/O
0); // template must be 0 for comm devices
if(m_hSerialPort == INVALID_HANDLE_VALUE)
return FALSE;
// set the timeout values
m_commTimeouts.ReadIntervalTimeout = 1000;
m_commTimeouts.ReadTotalTimeoutMultiplier = 1000;
m_commTimeouts.ReadTotalTimeoutConstant = 1000;
m_commTimeouts.WriteTotalTimeoutMultiplier = 1000;
m_commTimeouts.WriteTotalTimeoutConstant = 1000;
m_overlappedRead.Offset = 0;
m_overlappedRead.OffsetHigh = 0;
m_overlappedWrite.Offset = 0;
m_overlappedWrite.OffsetHigh = 0;
if(!SetupComm(m_hSerialPort, DEVICE_SNDBUF_SIZE, DEVICE_RCVBUF_SIZE)) //设置串口
{
tackleError("SetupComm Error.");
return FALSE;
}
if(!SetCommTimeouts(m_hSerialPort, &m_commTimeouts)) //设置串口超时事件
{
tackleError("SetCommTimeouts Error.");
return FALSE;
}
if(!SetCommMask(m_hSerialPort,dwCommEvents)) //设置串口?触发事件??
{
tackleError("SetCommMask Error.");
return FALSE;
}
if(!GetCommState(m_hSerialPort, &m_dcb)) //获取串口设备状态???
{
tackleError("GetCommState Error.");
return FALSE;
}
m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high!
if(!BuildCommDCB(szBaud, &m_dcb))
{
tackleError("BuildCommDCB Error.");
return FALSE;
}
if(!SetCommState(m_hSerialPort, &m_dcb))
{
tackleError("SetCommState Error.");
return FALSE;
}
PurgeComm(m_hSerialPort, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
return TRUE;
}
//---------------------------------------------------------------------------
//--处理错误信息 主要用于打开串口时返回各种错误信息,并关闭串口
//--------------------------------------------------------------------------
void CSerialPortEx::tackleError(const char* szError)
{
processErrorMessage(szError);
CloseHandle(m_hSerialPort);
m_hSerialPort = NULL;
}
//---------------------------------------------------------------------------
//--接收线程
//--------------------------------------------------------------------------
void CSerialPortEx::threadProc_Rcv(BOOL* pbRunSignal, CRITICAL_SECTION* pCriticalSection,
void* arg)
{
unsigned long dwEvent;
unsigned long dwCommEvent;
unsigned long dwError;
BOOL bResult;
try
{
if(m_hSerialPort)
PurgeComm(m_hSerialPort, PURGE_RXCLEAR | PURGE_RXABORT);
// PurgeComm(m_hSerialPort, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
while(*pbRunSignal)
{
bResult = WaitCommEvent(m_hSerialPort, &dwEvent, &m_overlappedRead); //等待串口的异步事件的激活
if(bResult) //清除错误
{
bResult = ClearCommError(m_hSerialPort, &dwError, &m_comstat);
if (m_comstat.cbInQue == 0)
continue;
}
else
{
switch (dwError = GetLastError())
{
case ERROR_IO_PENDING:
break;
case 87:
break;
default:
processErrorMessage("WaitCommEvent Error.");
break;
}
}
// m_waitInterval < 200 时,发生读取数据不全的概率较大
// 请说明 m_waitInterval 的间隔有何限制,主要是读的丢数的问题
dwEvent = WaitForMultipleObjects(2, m_hEventArray, FALSE, m_waitInterval); //判断是何种事件发送
switch(dwEvent)
{
case 0:
ResetEvent(m_hShutdownEvent); //设置关闭事件处于非触发状态
return;
case 1:
{
GetCommMask(m_hSerialPort, &dwCommEvent); //获取串口当前触发事件
if (dwCommEvent & EV_RXCHAR)
{
receive(*pbRunSignal);
}
break;
}
}
}
}
catch(char* err)
{
g_debugFile.AddText("Serial接收线程处理异常!");
return ;
}
}
void CSerialPortEx::threadProc_Snd(BOOL* pbRunSignal, CRITICAL_SECTION* pCriticalSection, void* arg)
{
}
//---------------------------------------------------------------------------
//--接收到信息处理 事件激发 则进行数据的接收 ,否则退出
//--------------------------------------------------------------------------
void CSerialPortEx::receive(BOOL bRunSignal)
{
if(!bRunSignal) //在关闭程序时有可能会先执行析构函数释放缓冲区,如果此时
return; //接收线程仍未停止,访问被释放的缓冲区会造成崩溃
BOOL bRead = TRUE;
BOOL bResult = TRUE;
DWORD dwError = 0;
int readSize = 0;
try
{
while(1)
{
EnterCriticalSection(m_pCriticalSection_Rcv);
bResult = ClearCommError(m_hSerialPort, &dwError, &m_comstat);
LeaveCriticalSection(m_pCriticalSection_Rcv);
if (m_comstat.cbInQue == 0)
{
// break out when all bytes have been read
break;
}
//进入读取数据的临界区,进行数据的读取
EnterCriticalSection(m_pCriticalSection_Rcv);
if (bRead)
{
bResult = ReadFile(m_hSerialPort, // Handle to COMM port
m_szReceiveBuffer, // RX Buffer Pointer
m_comstat.cbInQue, // Read all bytes
&m_dwReceiveSize, // Stores number of bytes read
&m_overlappedRead); // pointer to the m_ov structure
//log 记录读取状态
g_debugFile.ShowBuf("in ReadFile flag ="+BoolToStr(bResult)+ ", m_comstat.cbInQue = " +
IntToStr(m_comstat.cbInQue) + "m_dwReceiveSize = " +IntToStr(m_dwReceiveSize) +"\n",
(BYTE*)m_szReceiveBuffer, m_dwReceiveSize);
// deal with the error code
if (!bResult)
{
switch (dwError = GetLastError())
{
case ERROR_IO_PENDING:
{
// asynchronous i/o is still in progress
// Proceed on to GetOverlappedResults();
processErrorMessage("ReadFile ERROR_IO_PENDING.");
bRead = FALSE;
break;
}
default:
{
// Another error has occured. Process this error.
processErrorMessage("ReadFile Error.");
break;
}
}
}
else
{
// ReadFile() returned complete. It is not necessary to call GetOverlappedResults()
if(m_dwReceiveSize != m_comstat.cbInQue)
{
bRead = false;
// log 记录 读取字节不全,信号超时受信
// 请说明 什么情况下,会导致读取字节不全 m_dwReceiveSize != m_comstat.cbInQue的原因
g_debugFile.AddText("读取字节不全,信号超时受信 ReadFile flag ="+BoolToStr(bResult)+ ", m_comstat.cbInQue = " +
IntToStr(m_comstat.cbInQue) + "m_dwReceiveSize = " +IntToStr(m_dwReceiveSize));
}
else
{
bRead = TRUE;
}
}
} // close if (bRead)
if (!bRead)
{
g_debugFile.AddText("in GetOverlappedResults() in ReadFile()");
bRead = TRUE;
bResult = GetOverlappedResult(m_hSerialPort, // Handle to COMM port
&m_overlappedRead, // Overlapped structure
&m_dwReceiveSize, // Stores number of bytes read
TRUE); // Wait flag
// deal with the error code
if (!bResult)
{
processErrorMessage("GetOverlappedResults() in ReadFile()");
}
} // close if (!bRead)
// log 记录接收到的数据,并进行进行数据的接收处理
g_debugFile.ShowBuf( "串口接收数据 m_dwReceiveSize= " +IntToStr(m_dwReceiveSize) +"\n",
(BYTE*)m_szReceiveBuffer, m_dwReceiveSize);
if(fpRcvFunctionProc)
(*fpRcvFunctionProc)(m_pParent, m_szReceiveBuffer, m_dwReceiveSize);
LeaveCriticalSection(m_pCriticalSection_Rcv);
}
}
catch(char* err)
{
g_debugFile.AddText("Serial数据的接收处理调用异常!");
return ;
}
}
//---------------------------------------------------------------------------
//--发送数据到串口
//--------------------------------------------------------------------------
void CSerialPortEx::send()
{
g_debugFile.AddText("in CSerialPortEx::send()");
if(m_dwSendSize < 1)
return;
BOOL bResult = TRUE;
BOOL bSend = TRUE;
unsigned long dwBytesSent = 0;
// Gain ownership of the critical section
EnterCriticalSection(m_pCriticalSection_Snd);
// Initailize variables
m_overlappedWrite.Offset = 0;
m_overlappedWrite.OffsetHigh = 0;
// PurgeComm
// Clear buffer
// 请说明 PurgeComm 的间隔有何限制,主要是写的丢数的问题
PurgeComm(m_hSerialPort, PURGE_TXCLEAR | PURGE_TXABORT);
bResult = WriteFile(m_hSerialPort, // Handle to COMM Port
m_szSendBuffer, // Pointer to message buffer in calling finction
m_dwSendSize, // Length of message to send
&dwBytesSent, // Where to store the number of bytes sent
&m_overlappedWrite); // Overlapped structure
// deal with any error codes
if (!bResult)
{
unsigned long dwError = GetLastError();
switch (dwError)
{
case ERROR_IO_PENDING: //串口正在进行读写操作
{
// continue to GetOverlappedResults()
dwBytesSent = 0;
g_debugFile.AddText("WriteFile ERROR_IO_PENDING ");
bResult = GetOverlappedResult(m_hSerialPort, // Handle to COMM port
&m_overlappedWrite, // Overlapped structure
&dwBytesSent, // Stores number of bytes sent
TRUE); // Wait flag
LeaveCriticalSection(m_pCriticalSection_Snd);
// deal with the error code 等待操作完成,仍失败
if (!bResult)
{
bSend = false;
processErrorMessage("GetOverlappedResults() in WriteFile()");
}
break;
}
default:
{
// all other error codes
LeaveCriticalSection(m_pCriticalSection_Snd);
processErrorMessage("WriteFile() Error.");
bSend = false;
}
}
}
else
{
LeaveCriticalSection(m_pCriticalSection_Snd);
}
g_debugFile.AddText("out CSerialPortEx::send()");
return;
}
全部回复
-
Hi tongniuniu,
感谢在MSDN论坛发帖。
>>在应用中,采用异步的方式进行串口数据的收发,在silicon lab的usb转串口芯片上出现了,readfile返回值为true,但获取的 实际字节数与缓冲区可用字节数不等,由于范围为true,根据msdn的手册,就未执行GetOverlappedResult,通用通讯底层,在其他串口上未出现该现象,完整代码如下。请问导致该问题的原因是什么?
ReadFile函数返回true并不能说明字节已经完全读取。当你使用FILE_FLAG_OVERLAPPED打开hFile时,你需要注意以下几点:
- lpOverlapped参数必须指向有效且唯一的OVERLAPPED结构,否则该函数可能会错误地报告读操作完成。
- lpNumberOfBytesRead参数应设置为NULL。使用GetOverlappedResult函数来获取实际读取的字节数。如果hFile参数与I / O完成端口相关联,您还可以通过调用GetQueuedCompletionStatus函数获取读取的字节数。
希望对你有所帮助。
Best Regards,
Sera YuMSDN Community Support<br/> Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact <a href="mailto:MSDNFSF@microsoft.com">MSDNFSF@microsoft.com</a>.
-
谢谢你的耐心回答,先前对api函数的理解太肤浅了,看了Readfile的返回结果为true以为就是,读成功了,经过你的指点,我正在消化,ReadFile 与 GetOverlappedResult函数,你说的第一个问题,我是这样做的,第二个我还要去尝试下,另外,发现ReadFile里有讲一个例子“” Asynchronous Disk I/O Appears as Synchronous on Windows“这个我还没有看完,等我看完了,有问题再问你,再次感谢你的回答
》》ReadFile函数返回true并不能说明字节已经完全读取。当你使用FILE_FLAG_OVERLAPPED打开hFile时,你需要注意以下几点:
- lpOverlapped参数必须指向有效且唯一的overlapped结构,否则该函数可能会错误地报告读操作完成。
- lpNumberOfBytesRead参数应设置为NULL。使用 GetOverlappedResult函数来获取实际读取的字节数。如果hFile参数与I / O完成端口相关联,您还可以通过调用GetQueuedCompletionStatus函数获取读取的字节数。
希望对你有所帮助。
-
今天,我大致看完了msdn中readfile和GetOverlappedResult的内容,以及Asynchronous Disk I/O Appears as Synchronous on Windows;这里面的进行异步读文件的,还有以下几个疑问
1.GetOverlappedResult例子中判断readfile的返回结果是否为真,如果为真了,其判断为异步操作同步做完了,里面的注释我也是不太理解,是否是说大部分文件系统在第一次读取之后,会触发同步都操作?是怎么理解的?
2.我是在串口通讯中,用的异步的readfile的返回结果, 后面“Asynchronous Disk I/O Appears as Synchronous on Windows”一文里说,“For a disk device, typically, an I/O request can be completed "immediately" when the data is cached in memory.”,请问此时读取的字节数不可信,为何例子中还时在realdfile成功后,不用GetOverlappedResult重新获取实际字节数
3.如果收到字符后,同步完成读操作,这会的实际读取的字节为何不等于实际缓冲区的数据?
4.推荐的异步读取应该如何写
5.你的建议2里面的第2条,实际读取字节地址为何建议为空,这是为了Readfile肯定是异步完成还是其他原因?文中部分代码
if (!ReadFile(hFile, pDataBuf, dwSizeOfBuffer, &NumberOfBytesRead, &osReadOperation ) { if (GetLastError() != ERROR_IO_PENDING) { // Some other error occurred while reading the file. ErrorReadingFile(); ExitProcess(0); } else // Operation has been queued and // will complete in the future. fOverlapped = TRUE; } else // Operation has completed immediately. fOverlapped = FALSE; if (fOverlapped) { // Wait for the operation to complete before continuing. // You could do some background work if you wanted to. if (GetOverlappedResult( hFile, &osReadOperation, &NumberOfBytesTransferred, TRUE)) ReadHasCompleted(NumberOfBytesTransferred); else // Operation has completed, but it failed. ErrorReadingFile(); } else ReadHasCompleted(NumberOfBytesRead);
-
前几天,我在论坛提了,我用异步读取串口时,出现ReadFile读出的字节数与实际字节数不一致,经Sera Yu 指导,我大致看完了msdn中readfile和GetOverlappedResult的内容,以及Asynchronous Disk I/O Appears as Synchronous on Windows;这里面的进行异步读文件的,有以下几个疑问
1.GetOverlappedResult例子中判断readfile的返回结果是否为真,如果为真了,其判断为异步操作同步做完了,里面的注释我也是不太理解,是否是说大部分文件系统在第一次读取之后,会触发同步都操作?是怎么理解的?
2.我是在串口通讯中,用的异步的readfile的返回结果, 后面“Asynchronous Disk I/O Appears as Synchronous on Windows”一文里说,“For a disk device, typically, an I/O request can be completed "immediately" when the data is cached in memory.”,请问此时读取的字节数不可信,为何例子中还时在realdfile成功后,不用GetOverlappedResult重新获取实际字节数
3.如果收到字符后,同步完成读操作,这会的实际读取的字节为何不等于实际缓冲区的数据?
4.推荐的异步读取应该如何写
5.异步读取时,建议实际读取字节地址为何建议为空,这是为了Readfile肯定是异步完成还是其他原因?文中部分代码
if (!ReadFile(hFile, pDataBuf, dwSizeOfBuffer, &NumberOfBytesRead, &osReadOperation ) { if (GetLastError() != ERROR_IO_PENDING) { // Some other error occurred while reading the file. ErrorReadingFile(); ExitProcess(0); } else // Operation has been queued and // will complete in the future. fOverlapped = TRUE; } else // Operation has completed immediately. fOverlapped = FALSE; if (fOverlapped) { // Wait for the operation to complete before continuing. // You could do some background work if you wanted to. if (GetOverlappedResult( hFile, &osReadOperation, &NumberOfBytesTransferred, TRUE)) ReadHasCompleted(NumberOfBytesTransferred); else // Operation has completed, but it failed. ErrorReadingFile(); } else ReadHasCompleted(NumberOfBytesRead);
- 已编辑 tongniuniu 2017年7月2日 13:53
- 已合并 Baron Bi 2017年7月20日 3:02 same case
-
Hi,
>>1.GetOverlappedResult例子中判断readfile的返回结果是否为真,如果为真了,其判断为异步操作同步做完了,里面的注释我也是不太理解,是否是说大部分文件系统在第一次读取之后,会触发同步都操作?是怎么理解的?
你具体指的哪段注释,请详细说明一下。
>>2.我是在串口通讯中,用的异步的readfile的返回结果, 后面“Asynchronous Disk I/O Appears as Synchronous on Windows”一文里说,“For a disk device, typically, an I/O request can be completed "immediately" when the data is cached in memory.”,请问此时读取的字节数不可信,为何例子中还时在realdfile成功后,不用GetOverlappedResult重新获取实际字节数大多数I / O驱动程序(磁盘,通信和其他)都有特殊的代码,如果I / O请求可以“立即完成”,这个时候操作已经完成,ReadFile或WriteFile函数将返回TRUE,形成类似同步操作的现象。所以不需要GetOverlappedResult再检测了。但是通常情况下,并不建议你这么做。建议你使用FILE_FLAG_NO_BUFFERING标志,它指示文件系统根本不使用任何缓存机制。这可以确保I / O请求实际上是真实的异步操作。
>>3.如果收到字符后,同步完成读操作,这会的实际读取的字节为何不等于实际缓冲区的数据?当你使用同步操作时,系统会做以下操作。
如果lpOverlapped为NULL,则读取操作从当前文件位置开始,并且ReadFile不会返回,直到操作完成,并且系统在ReadFile返回之前更新文件指针。如果lpOverlapped不为NULL,则读取操作从OVERLAPPED结构中指定的偏移开始,并且ReadFile在读操作完成之前不返回。 在ReadFile返回之前,系统会更新OVERLAPPED偏移量。当同步读取操作到达文件的末尾时,ReadFile返回TRUE,并将* lpNumberOfBytesRead设置为零。
更多关于异步和同步的操作,可以参考以下文档。
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
>>4.推荐的异步读取应该如何写
这里有篇示例,你可以参考一下。
https://code.msdn.microsoft.com/windowsdesktop/CppAsynchronousIO-a3f7c07d
希望对你有所帮助。
Best Regards,
Sera YuMSDN Community Support<br/> Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact <a href="mailto:MSDNFSF@microsoft.com">MSDNFSF@microsoft.com</a>.