重叠的套接字IO:WSAGetOverlappedResult失败,出现996错误代码

时间:2016-02-04 18:00:34

标签: windows networking winsock

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

// 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标志设置为       FALSE)在轮询模式下确定何时重叠       操作已经完成,得到此错误代码,直到       操作完成。请注意,此错误由返回       操作系统,因此错误号可能会改变       未来版本的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;
    }

1 个答案:

答案 0 :(得分:2)

错误代码996为WSA_IO_INCOMPLETE,如您所述,其记录如下:

  

应用程序已尝试确定重叠操作的状态尚未完成。在轮询模式下使用WSAGetOverlappedResultfWait标志设置为FALSE )以确定重叠操作何时完成的应用程序,请获取此错误代码,直到操作已完成

实际上,您将fWait参数设置为FALSE,因此错误是完全正常的行为。由于您正在轮询州,因此您必须在循环中致电WSAGetOverlappedResult(),直到停止报告WSA_IO_INCOMPLETE

否则,将fWait参数设置为TRUE,让它阻塞调用线程,直到I / O操作完成。