我正在维护一个旧的 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;
}
错误代码 996 是
WSA_IO_INCOMPLETE
,正如您所指出的,其记录如下:
应用程序已尝试确定重叠操作的状态尚未完成。在轮询模式下使用
(且WSAGetOverlappedResult
标志设置为 FALSE)来确定重叠操作何时完成的应用程序,将获取此错误代码 直到操作完成。fWait
事实上,您将
fWait
参数设置为 FALSE,因此该错误是完全正常的行为。由于您正在轮询状态,因此您必须循环调用 WSAGetOverlappedResult()
,直到它停止报告 WSA_IO_INCOMPLETE
。
否则,请将
fWait
参数设置为 TRUE,并让它阻塞调用线程,直到 I/O 操作完成。
我在flutter中使用串行通信,出现了这个错误。 经过大量研究后,我发现此错误的原因是我正在发送读取请求,而我的超时/等待响应时间是无限或太长,并且在完成第一个请求之前或在获得响应之前,我正在发送另一个读取请求为什么会出现这个错误。