Re: Multiple instances of CAsyncSocket in same thread
On Apr 2, 8:07 pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
The problem is not CAsyncSockets in the same thread; the problem is that =
you have deleted
a socket which had pending I/O, so you screwed up in deleting the object =
before you get a
connection failure back. You have to close the socket completely, incl=
uding a shutdown
call. But if a connection is pending, it is not clear that this does n=
ot result in a race
condition. Do not delete the socket until you know, from its OnConnect=
notification, that
it has failed to connect.
There's no reason to show us the code. The code is correct. You bro=
ke the assumptions it
is based on.
Also, please use correct terminology. If the ENSURE macro is causing a=
nything to happen,
it is causing an assertion failure, not an exception. Note that the pr=
oblem is that the
socket is not in the handle map, because you deleted it. You need to f=
igure out which
callback is being invoked. Do not delete the object until this callbac=
k has completed.
joe
On Thu, 2 Apr 2009 14:35:26 -0700 (PDT), PDB <paul.buschme...@iseinc-onli=
ne.com> wrote:
I have a problem with multiple sockets in the same CWinThread derived
thread. Here is the issue.
1) Instantiate two CAsyncSocket derived instances which connect
immediately, and all is well.
2) Instantiate one CAsyncSocket derived instance which connects
immediately, and another which does not. I use a timer to monitor the
socket which is not connected, and then close the socket and delete
the instance if it does not connect within the timeout period. This
causes an exception in CAsyncSocket::DoCallBack (I've included a code
scrap). The ENSURE macro is the causing the exception because pSocket
= NULL.
void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
{
if (wParam == 0 && lParam == 0)
return;
// Has the socket be closed - lookup in dead handle list
CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wPa=
ram,
TRUE);
// If yes ignore message
if (pSocket != NULL)
return;
pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE);
if (pSocket == NULL)
{
// Must be in the middle of an Accept call
pSocket = CAsyncSocket::LookupHandle(INVALID_S=
OCKET, FALSE);
ENSURE(pSocket != NULL);
if(pSocket == NULL)
return;
pSocket->m_hSocket = (SOCKET)wParam;
CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE=
);
CAsyncSocket::AttachHandle(pSocket->m_hSocket, p=
Socket, FALSE);
}
The problem only occurs if one socket connects and the other doesn't
and the time out causes the socket not connected to be closed and
deleted. Note: It is the closing of the socket that causes the
problem, not deleting the pointer to the instance of the socket.
I've also noticed that if I open a listening socket in the thread,
then create an instance of a socket that doesn't connect and the time
out causes it to be closed and delete will result in the same
exception.
Lastly, if I turn off the timer and do not overtly close and delete
the socket that is not connected, everything is fine.
While I appreciate that it is not great form to have lots of sockets
on the same thread (for lots of performance reasons), it should work.
Any explanation will be appreciated.
P.S. The article at Flounder.com "A Rewrite of KB192570: An MFC
Asynchronous Socket Example Done Right" has been invaluable, THANK
YOU! We've been using CSocket for years and have always been
concerned about that implementation, we are working on making the app
more robust.
Joseph M. Newcomer [MVP]
email: newco...@flounder.com
Web:http://www.flounder.com
MVP Tips:http://www.flounder.com/mvp_tips.htm
I did some more testing. The message that comes back is the
FD_CONNECT message. It gets invoked by the calling CAsyncSocket::Close
(), which, of course, also deletes the socket object from the map. My
timeout works properly with with only one socket, because the window
providing the notifications is destroyed, hence the FD_CONNECT message
is never sent. For the UI case, we added a boolean variable to
indicate a FD_CONNECT message was pending, and we use it to disable
the DISCONNECT button, so the user cannot cause the assertion
failure. In the thread case, where there is no user interaction, we
just let the WSASocket timeout prevail.
We use sockets in threads, and we may need to terminate the thread
while the FD_CONNECT notification is pending. My tests show that when
the thread cleans up by closing all sockets, connected or not, deletes
the CAsyncSocket derived objects, the assertion failure does not
occur. Our intent in all of this has been to be rid of the blocking
behavior of CSocket. We want to be able to terminate the threads
cleanly, especially(!) when the socket is waiting to connect.
The bottom line is, it appears there is no way to terminate the
connection process before it times out at the WSASocket level using
CAsyncSocket, but I welcome any discussion to the contrary.
Thanks to all for the insight.