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
| Вернуться в корень Архива
|