windows 重叠套接字IO:WSAGetOverlappedResult失败,错误代码为996

2lpgd968  于 2023-10-22  发布在  Windows
关注(0)|答案(2)|浏览(231)

我正在维护一个旧的Windows应用程序,有一个问题我一直无法解决。在新的硬件上,在各种操作系统下,我们已经开始看到我们从未见过的错误,在过去它一直非常稳定。它打开一个UDP套接字并将其配置为广播UDP数据。然后它会产生数据流。代码使用重叠IO,因此它有一个线程在线程中等待重叠IO事件。socket是这样打开的:

// Create datagram socket
if (!SocketDgCreate(&m_SDGScan, pstAppState->szScannerIP, (short)nPort)){
    StatusMessage(MSG_ERR, "socket create failed on '%s' Port %u\r\n",
            pstAppState->szScannerIP, nPort);
    return false;
}

// Configure datagram socket for broadcast
int nSockOpt = TRUE;

if (setsockopt(m_SDGScan,
            SOL_SOCKET, 
            SO_BROADCAST, 
            (LPSTR)&nSockOpt, 
            sizeof(nSockOpt)) == SOCKET_ERROR){
    StatusMessage(MSG_ERR, "socket broadcast failed\r\n\t%s\r\n", 
        WSAGetLastErrorStr());
    return false;
}

// Allow the socket to be bound to an address already in use.
if (setsockopt(m_SDGScan, 
            SOL_SOCKET, 
            SO_REUSEADDR,
            (LPSTR)&nSockOpt, 
            sizeof(nSockOpt)) == SOCKET_ERROR){
    StatusMessage(MSG_ERR, "socket reuse address failed\r\n\t%s\r\n", 
        WSAGetLastErrorStr());
    return false;
}

在新的硬件上,当我们打开套接字时,我们会得到错误996,Microsoft定义为:
重叠的I/O事件对象未处于信号状态。应用程序试图确定尚未完成的重叠操作的状态。在轮询模式下使用WSAGetOverlappedResult(将fWait标志设置为“否”)来确定重叠操作何时完成的应用程序会收到此错误代码,直到操作完成为止。请注意,此错误是由操作系统返回的,因此错误号可能会在Windows的未来版本中更改。
使用winsock发送数据的代码似乎通过处理错误代码并验证它没有挂起来做正确的事情。

int nSendRet = WSASendTo(m_SDGScan, 
                    &m_astSendBuff[m_nSendCtr],
                    1,
                    &nNumSentImmed, 
                    0, 
                    (LPSOCKADDR)&m_scanDGDestAddr, sizeof(SOCKADDR),
                    &m_scanDGOverlapped, 
                    NULL);          // Use event signal upon completion.

if (nSendRet == 0){
    // Sent immediately
    ++m_nSendCtr;
    if (m_nSendCtr == m_nNumQueued) {
        m_nSendCtr = m_nNumQueued = 0;
    }
}else if (nSendRet == SOCKET_ERROR) {
    // This could just be an overlap in progress state!
    int err = WSAGetLastError();
    if (err == WSA_IO_PENDING)  {
        // If the error indicates I/O pending then the Overlapped operation
        // was successfull and will complete later!
        SetEvent( m_hScanDGEvent );
    }

实际触发错误的代码在它自己的线程中,看起来像这样:

UINT CXyz::Thread(LPVOID){

bool fEventSelect = true;
WSANETWORKEVENTS networkEvents;

DWORD dwOvlRslt = 0;
DWORD dwWaitVal;
DWORD dwNumSent;

// Turn on the XYZ datagram stuff.
// Load event into overlapped I/O structures
m_scanDGOverlapped.hEvent = m_hScanDGEvent;
ResetEvent(m_hScanDGEvent);

// Setup the events.
const int nNumEvents = 2;
HANDLE ahEvents[nNumEvents];
ahEvents[0] = m_hScanDGEvent;   // XYZ datagrams.
ahEvents[1] = m_hThreadStopEvent;

// Thread now alive!
m_fThreadAlive = true;

// Associate scan transmit event with socket, but no state yet (will be overridden)

if (WSAEventSelect(m_SDGScan, m_hScanDGEvent, FD_READ) == SOCKET_ERROR) {
    StatusMessage(MSG_ERR, "XYZ DG event select failed 1 [%s]\r\n",
        WSAGetLastErrorStr());
}

// Thread loop processing...
bool bDone = false;
    dwWaitVal = WaitForMultipleObjectsEx(nNumEvents, ahEvents, FALSE, INFINITE, FALSE);

    // Acq buffer done or delay timer expired
    switch (dwWaitVal)
    {
    case WAIT_FAILED:               // Bad,
        StatusMessage(MSG_ERR, "XYZ thread aborting [%d]\r\n", GetLastError());
        bDone = true;
        break;

    case WAIT_OBJECT_0:             // XYZ datagrams.
        // Clears internal records and resets event object

        // Clears internal records and resets event object
        if (WSAEnumNetworkEvents(m_SDGScan, m_hScanDGEvent, &networkEvents) ==
                SOCKET_ERROR){
            StatusMessage(MSG_ERR, "XYZ WSAEnumNetworkEvents() failed [%s]\r\n",
                    WSAGetLastErrorStr());
            bDone = true;
        }else if (!WSAGetOverlappedResult(
                            m_SDGScan,
                            &m_scanDGOverlapped,
                            &dwNumSent,
                            FALSE,
                            &dwOvlRslt)){
            // Get status of last send
            StatusMessage(MSG_ERR, "WSAGetOverlappedResult() failed [%s]\r\n",WSAGetLastErrorStr());
           }else{
               // Handle next packet code omitted
           }

    case (WAIT_OBJECT_0+1):         // Shutdown.
        bDone = true;
        break;

    default:
        break;
    }
dsf9zpds

dsf9zpds1#

错误代码996是WSA_IO_INCOMPLETE,正如您所注意到的,记录如下:
应用程序试图确定一个重叠操作的状态**,但该操作尚未完成**。在轮询模式下使用WSAGetOverlappedResultfWait标志设置为“否”)来确定重叠操作何时完成的应用程序,会收到此错误代码**,直到操作完成**。
实际上,您正在将fWait参数设置为,因此错误是完全正常的行为。由于您正在轮询状态,因此必须在循环中调用WSAGetOverlappedResult(),直到它停止报告WSA_IO_INCOMPLETE
否则,将fWait参数设置为TRUE,让它阻塞调用线程,直到I/O操作完成。

pn9klfpd

pn9klfpd2#

我正在使用flutter中的串行通信,出现了此错误。经过大量的研究,我发现这个错误的原因是我正在发送读请求,我的超时/等待响应时间是无限的或太长,在完成第一个请求或获得响应之前,我正在发送另一个读请求,这就是为什么这个错误来了。

相关问题