Accessing CSocket in secondary thread
Helge Bredow -- Helge_Bredow.DOLA@notes.dola.wa.gov.au Friday, August 30, 1996 Environment: VC++ 4.0, NT 3.51 I am writing a TCP/IP server program that listens at a socket for incoming requests in it's primary thread. For each request that is received, it spawns a new secondary thread, passing the socket created by the CAsyncSocket::Accept method in the thread function's pParam parameter. Spawning a thread for each connection appears to me to be the kind of thing that most server applications would want to do, yet I get an assertion failure on the socket handle in the secondary thread. This happens when I try to create an archive from a CSocketFile that is associated with the new connection socket. I know MFC has some problems accessing objects in a thread which are encapsulations of handles - the solution for GDI objects is to pass the handle and create the object by using the ::FromHandle method. This does not work for CSocket classes since the CAsyncSocket::FromHandle method does not return an object unless it can find one in it's handle <-> object map. Can anyone help me out on this? Helge
Poul A. Costinsky -- Poul@wizsoft.com Sunday, September 01, 1996 Hi Helge! I probably have a solution for you - look at my homepage at http://www.wizsoft.com/~poul/srs/. In short, I found CSocket incompatible with multithreading and some 100000 slower then WinSock API, so I wrote a small class over WinSock API (and another small class for handling a threads). BTW, any MFC developers here - how did you achieved this 100000 performance gap? It must be really hard! Hope this helps. Regards, Poul. ("`-''-/").___..--''"`-._ ~~~~~~~~~~Poul A. Costinsky~~~~~~~~~~ (`6_ 6 ) `-. ( ).`-.__.`) Poul@wizsoft.com (_Y_.)' ._ ) `._ `. ``-..-' PoulACost@msn.com _..`--'_..-_/ /--'_.' ,' (il).-'' (li).' ((!.- http://www.wizsoft.com/~Poul ---------- From: Helge Bredow Sent: Friday, August 30, 1996 1:08 PM To: mfc-l Subject: Accessing CSocket in secondary thread Environment: VC++ 4.0, NT 3.51 I am writing a TCP/IP server program that listens at a socket for incoming requests in it's primary thread. For each request that is received, it spawns a new secondary thread, passing the socket created by the CAsyncSocket::Accept method in the thread function's pParam parameter. Spawning a thread for each connection appears to me to be the kind of thing that most server applications would want to do, yet I get an assertion failure on the socket handle in the secondary thread. This happens when I try to create an archive from a CSocketFile that is associated with the new connection socket. I know MFC has some problems accessing objects in a thread which are encapsulations of handles - the solution for GDI objects is to pass the handle and create the object by using the ::FromHandle method. This does not work for CSocket classes since the CAsyncSocket::FromHandle method does not return an object unless it can find one in it's handle <-> object map. Can anyone help me out on this? Helge
Phil Daley -- pdaley@relay.com Tuesday, September 03, 1996 At 11:08 AM 8/30/96, you wrote: >Environment: VC++ 4.0, NT 3.51 > >I am writing a TCP/IP server program that listens at a socket for >incoming requests in it's primary thread. For each request that is >received, it spawns a new secondary thread, passing the socket created >by the CAsyncSocket::Accept method in the thread function's pParam >parameter. > >Spawning a thread for each connection appears to me to be the kind of >thing that most server applications would want to do. Exactly, this is what most every server does. We had to rewrite the MFC CSocket classes. They were hopelessly inadequate. Phil Daley Relay Technology http://www.conknet.com/~p_daley
Rommel Songco -- rsongco@spectrasoft.com Wednesday, September 04, 1996 [Mini-digest: 2 responses] Hi there! In your overriden OnAccept function, create a new client socket object and call CAsyncSocket::Accept. What you need to do is to detach the handle of this client socket object and pass it to your secondary thread. In your secondary thread, do _not_ call the FromHandle method since the handle passed to it doesn't have an entry yet in that thread's handle map. Instead, create a new socket object and attach the handle received to that object. Best Regards, Rommel rsongco@spectrasoft.com > ---------- > From: Helge Bredow > Sent: Friday, August 30, 1996 1:08 PM > To: mfc-l > Subject: Accessing CSocket in secondary thread > > Environment: VC++ 4.0, NT 3.51 > > I am writing a TCP/IP server program that listens at a socket for > incoming requests in it's primary thread. For each request that is > received, it spawns a new secondary thread, passing the socket created > by the CAsyncSocket::Accept method in the thread function's pParam > parameter. > > Spawning a thread for each connection appears to me to be the kind of > thing that most server applications would want to do, yet I get an > assertion failure on the socket handle in the secondary thread. This > happens when I try to create an archive from a CSocketFile that is > associated with the new connection socket. I know MFC has some problems > accessing objects in a thread which are encapsulations of handles - the > solution for GDI objects is to pass the handle and create the object by > using the ::FromHandle method. This does not work for CSocket classes > since the CAsyncSocket::FromHandle method does not return an object > unless it can find one in it's handle <-> object map. > > Can anyone help me out on this? > > Helge -----From: "Dan Maher"I came across this same problem a while ago. This may not be the best solution, but here's what I did. In my OnAccept, I set a member variable (of type SOCKET) of my new thread to the return value of CAsyncSocket::Detach() - this is the handle of the listening socket. I signal to my new thread that a connection has come in and block until the new thread is finished with the handle. Once the new thread is finished, I reconnect the handle to my CAsyncSocket using Attach(). In my new thread, I wait for the connection event. Once the event is signaled, I connect a temporary CAsyncSocket to the handle represented by the member variable assigned above, and call CAsyncSocket::Accept() with my new thread's CAsyncSocket member variable that it created. Then I detach the temporary and pass the handle back to the main thread through the new thread's member variable. Sound confusing? Well, it is. This may not be the most elegant solution, but it's the only way I have found to create the new socket so that it is actually running within the context of the new thread. Using CAsyncSocket::Accept() within the main thread creates the socket within the context of the main thread and this causes a problem if the main thread is blocked for any reason. It can also cause a serious performance hit if you have multiple simultaneous connections. Here's some sample code that might clear things up a bit: /* --- In the main thread --- */ void CMySocket::OnAccept( int nErrorCode) { /* m_MyNewThread is of a type derived from CWinThread m_pLstnSocket is a pointer to a CAsyncSocket derived class m_listen is of type SOCKET */ m_MyNewThread->m_listen = m_pLstnSocket->Detach(); m_MyNewThread->evConnection.SetEvent(); // Signal the new thread Sleep( 50); // release timeslices to wait for the new thread to get the event. m_MyNewThread->evConnection.Lock(); // Wait for the new thread to finish m_pLstnSocket->Attach( m_MyNewThread->m_listen); // re-attach to my listening socket } /* -- In the New Thread ---*/ BOOL CMyNewThread::InitInstance() { CAsyncSocket listen; // Temporary variable for the accept call... if (evConnection.Lock( )) { m_pSocket = new CMySocket(); listen.Attach( m_listen); listen.Accept( *m_pSocket); m_listen = listen.Detach(); // make sure handle is up-to-date evConnection.SetEvent(); // Signal the main thread that we're done... } } Hopefully this clears things up a bit. This seems to perform fairly well. (I haven't really done any serious performance tests, but it does well enough for my requirements). dM
| Вернуться в корень Архива |