Keeping socket events coming and receiving all data
From: MWFox (MWFox_at_discussions.microsoft.com)
Date: 08/18/04
- Next message: Bill Thompson: "Re: pack a data file into EXE application"
- Previous message: Bill Thompson: "Re: Problem Creating numerous edit control's in custom control"
- Messages sorted by: [ date ] [ thread ]
Date: Tue, 17 Aug 2004 21:37:01 -0700
We're using CSocket, CSocketFile, and CArchive in our project. In an effort
to keep this posting as streamlined as possible, I ask you to read first my
original posting which describes the problem I was seeing and the environment
in more detail. Please refer to "WM_SOCKET_NOTIFY just stops", dated
8/4/2004.
The reply I received from George N to the original posting boosted my
confidence in my approach to a workaround. I understood George's answer to
mean this: as long as I reenable socket event notification before our
thread's message loop runs again, there likely won't be any loss of events.
An additional concern which I am expressing here for the first time is that
it seems possible for there to be a race condition between our thread's
process of reenabling socket event notification and the background socket
thread's activity of handling port I/O.
In an effort to eliminate these cases I wrote the following code.
Have I covered both cases: 1) keeping WM_SOCKET_NOTIFY events alive and 2)
preventing the accidental loss of data?
Have I shown you enough code for you to answer?
Advice is greatly appreciated.
-Mary
---------------------------------------------
bool CsConnection::EnableSocketIOEvents(void)
{
bool bIsSuccess = true;
if (!IsEmpty())
{
if (!m_pSocket->AsyncSelect())
{
bIsSuccess = false;
int nErrorCode = GetLastError();
blah blah blah
}
}
return bIsSuccess;
}
---------------------------------------------
int CsConnection::PollForSocketData(void)
{
int nRetVal = -2; // default value; means port is not initialized
if (m_pSocket && m_pSocketFile && m_pArcOut)
{
if (!m_bIsCanceled)
{
// Note: this is based on the logic in MFC's sockcore.cpp
// when processing a WM_SOCKET_NOTIFY socket window event
// to read from the port
int nErrorCode=0;
fd_set fds;
int nReady;
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(m_pSocket->m_hSocket, &fds);
nReady = select(0, &fds, NULL, NULL, &timeout);
if (nReady == SOCKET_ERROR)
nErrorCode = WSAGetLastError();
// nReady == 1 means the one specified socket is ready for reading
if ((nReady == 1) || (nErrorCode != 0))
{
TRACE_IT(_T("Poll - Calling OnReceive() to serialize.\n"));
m_pSocket->OnReceive(nErrorCode);
}
nRetVal = nReady;
}
}
return nRetVal;
}
---------------------------------------------
UINT CsConnectionThread::MessageLoop(LPVOID lpParam)
{
CsConnection *pConnection = (CsConnection *)lpParam;
ASSERT(pConnection);
CsConnectionErrorHandler *pRegisteredErrorHandler=NULL;
BOOL bResetSuccess = FALSE;
LRESULT lResult = CONN_SUCCESS;
// allocate array to hold "waitable objects" to wakeup up on
INT nCntEvents = 8;
HANDLE aEvents[8];
// fill the array with handles to the "waitable objects"
aEvents[0] = pConnection->GetReqOutWakeup();
. . .
aEvents[7] = pConnection->GetHousekeepingTimer(); // waitable timer #3
while (TRUE)
{
DWORD result ;
MSG msg ;
if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// WORKAROUND #1 for WM_SOCKET_NOTIFY stoppage:
// In case socket i/o thread beat EnableSocketIOEvents() to its
completion
// in this possible race condition, poll the socket port for
// status and process data at the port if necessary.
if (pConnection->PollForSocketData() == 0)
{
// If nothing at port, reenable WM_SOCKET_* events for good measure.
// It is possible that earlier we inadvertantly disabled
WM_SOCKET_*
// events by reading data at the port that was intended to be
// associated with a WM_SOCKET_NOTIFY we haven't processed yet.
pConnection->EnableSocketIOEvents();
}
}
else
{
if (msg.message == WM_QUIT)
{
return msg.wParam;
}
// Otherwise, dispatch the WM_SOCKET_* message
// to the socket window inherently associated with this thread.
DispatchMessage(&msg);
}
// This is the regular Windows message processing loop.
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
return msg.wParam;
}
// Otherwise, dispatch the WM_SOCKET_* message
DispatchMessage(&msg);
}
// Wait for any message sent or posted to this thread's message queue
// or for one of the passed handles be set to signaled.
result = MsgWaitForMultipleObjectsEx(nCntEvents, aEvents, INFINITE,
QS_ALLINPUT, MWMO_INPUTAVAILABLE);
// WORKAROUND #2 for WM_SOCKET_NOTIFY stoppage:
// Request socket thread to notify this thread of socket i/o
// by sending WM_SOCKET_* windows messages.
// Performance is best if done after call to MWMOEx().
pConnection->EnableSocketIOEvents();
if (result == (WAIT_OBJECT_0 + nCntEvents))
{
continue;
}
else
{
// event became signaled.
if (result - WAIT_OBJECT_0 == 0)
{
. . . handle event . . .
}
else if (result - WAIT_OBJECT_0 == 1)
{
. . . handle event . . .
}
. . . etc. . . .
}
} // end forever loop
} //---End of CsConnectionThread::MessageLoop
P.S. Replies to these postings were also helpful:
"CAsyncSocket::Send does not appear to send a WM_SOCKET_NOTIFY"
and "BUG in Winsock on P4 HT CPU"
- Next message: Bill Thompson: "Re: pack a data file into EXE application"
- Previous message: Bill Thompson: "Re: Problem Creating numerous edit control's in custom control"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|