C++ 串行端口不工作的Win32 IOCP

C++ 串行端口不工作的Win32 IOCP,c++,windows,serial-port,iocp,C++,Windows,Serial Port,Iocp,在收集了更多信息后,我编辑了这个问题。我正在尝试使用IOCP通过串行端口进行通信 我打开带有重叠标志的串行端口: HANDLE hComm = CreateFile(strPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 然后我将“hComm”与IOCP端口相关联 我正在使用ReadFile()启动一个从串行端口

在收集了更多信息后,我编辑了这个问题。我正在尝试使用IOCP通过串行端口进行通信

我打开带有重叠标志的串行端口:

HANDLE hComm = CreateFile(strPortName,
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED,
    NULL);
然后我将“hComm”与IOCP端口相关联

我正在使用ReadFile()启动一个从串行端口读取的重叠请求。我使用ReadFile()的方式如下:

bool bQueued = false;
DWORD dwRead;
BOOL bResult = ReadFile(GetCommHandle(), lpOverlapped->pbBufferData, lpOverlapped->dwBufferSize, &dwRead, (OVERLAPPED*)lpOverlapped);
if (bResult)
{
    // It completed, but will still trigger the completion routine, so don't need to queue another one here.
    bQueued = true;
}
else
{
    DWORD dwError = GetLastError();
    if (ERROR_IO_PENDING == dwError)
    {
        bQueued = true;
    }
    else
    {
        LogQueueReceiveError(lpOverlapped, dwError);

        ResetConnection();
    }
}
对ReadFile()的调用总是立即返回一个“true”结果,因此IOCP请求排队。但是,只有当指定的字节数到达串行端口时,操作才会完成。在我的代码中,调用ReadFile()时,接收缓冲区的大小是要读取的字节数(这是处理套接字时的方式)

如果我将要读取的字节数更改为1,那么一旦数据到达端口,操作就完成。同样,如果我将要读取的字节数更改为8,则当第八个字节到达端口时,操作完成,以此类推


如果我不知道预期的字节数,如何在串行端口上使用IOCP,而不一次读取一个字节,这似乎非常低效?

您可以使用
setcommtimeout
来更改此行为

很久以前(大约在2000年?)我也遇到过类似的问题,所以我相信目标操作系统是WindowsNT4

我的实现以IOCP上的一系列排队单字节读取结束。虽然您可以使用
SetCommTimeouts
设置允许部分读取,但此时您需要为计时器支付一个时间片,以便为您提供部分填充的缓冲区。对于应用程序,这引入了不可接受的延迟(10ms或16ms,取决于SMP与非SMP)


从那时起,世界可能已经发生了变化,或者延迟的时间片对您来说是可以接受的。无论哪种方式,尝试
SetCommTimeouts
都可能有用。

您可以使用
SetCommTimeouts
来更改此行为

很久以前(大约在2000年?)我也遇到过类似的问题,所以我相信目标操作系统是WindowsNT4

我的实现以IOCP上的一系列排队单字节读取结束。虽然您可以使用
SetCommTimeouts
设置允许部分读取,但此时您需要为计时器支付一个时间片,以便为您提供部分填充的缓冲区。对于应用程序,这引入了不可接受的延迟(10ms或16ms,取决于SMP与非SMP)

从那时起,世界可能已经发生了变化,或者延迟的时间片对您来说是可以接受的。无论哪种方式,尝试设置通信超时都可能有用

串行端口不工作的Win32 IOCP

这当然不是事实。IOCP在这里工作得很好-只有当挂起的io请求完成或取消时,数据包才会排队等待IOCP。因此,以通常的方式使用IOCP。您的问题不在IOCP中,而是在读取时串行驱动程序的行为中

我发现。。。在完成了这么多字节之后,它就完成了 到了

实际上,这是一种行为:

Serial.sys继续传输字节,直到达到请求的字节数 传输字节或发生超时事件

或更详细的(等于):

当 传输指定数量的字节或请求的读或写操作 写入操作超时。请求返回
状态\u SUCCESS
状态代码,指示指定的字节数已被删除 转移。超过此最大值的读取请求在以下情况下完成: 超时发生,并返回
状态\u超时
状态代码。这个
信息
输入/输出状态块的字段指示 超时发生前已成功读取字节

所以你有两个选择:

  • 始终将nNumberOfBytesToRead设置为1-在本例中为读取请求 数据到达端口后立即完成
  • 通过或直接发送设置一些超时 控制代码(这是相同的)
可能的最佳用途如下:

如果ReadIntervalTimeoutReadTotalTimeOut乘法器都是 设置为MAXULONG,并且ReadTotalTimeoutConstant设置为 值大于0且小于MAXULONG,这是一个读取请求 表现如下:

  • 如果串行端口的输入缓冲区中有任何字节,则读取请求将立即完成,并包含缓冲区中的字节
    并返回状态\u成功状态代码
  • 如果输入缓冲区中没有字节,串行端口将等待一个字节到达,然后立即完成读取请求 使用一个字节的数据并返回状态\u SUCCESS状态
    代码
  • 如果在ReadTotalTimeoutConstant指定的时间内没有字节到达,则读取请求超时,将I/O状态块的信息字段设置为零,并返回状态代码
还需要记住,win32层几乎总是丢失状态,即>0(因此
status\u TIMEOUT
)。只有在使用时,您才能直接获得它(在回调中-这里的dwErrorCode实际上是
NTSTATUS
code)。如果您使用-IoResult==0在超时时已进入(但将被
(NTSTATUS)重叠->内部==STATUS\u timeout
)。如果您使用自己的
IOCP
,并且-它再次丢失了
状态\u超时
-它只需返回带有此代码的已完成数据包的
TRUE
,而不设置上次错误。但是,在这种情况下,仍然将是
(NTSTATUS)lpOverlapped->Internal==STATUS\u TIMEOUT
(不要将出列数据包与
STATUS\u TIMEOUT
代码和当
GetQueuedComple