Discussion:
CSocket + MultiThreading = Fail to call OnReceive()???
(too old to reply)
Todor Atanasov
2013-07-02 06:13:07 UTC
Permalink
Hi Guys,

Just before I start, I know CSocket are advised not to be used, but I need CSocketFile in order to use CArchive, so I have no other option for now.

What I'm doing is I have one thread that listens for incoming connection, then accepts it and creates a new thread to handle the connection. I am doing everything there has to be done ( at least I think I am :D). So I detach the socket, and attach it in the new thread. But there is the problem, the OnReceive() is never called. The thread is UI, created like this:

CSocket soc;
Accept(soc);

CConnectThread* pThread = (CConnectThread*)AfxBeginThread(RUNTIME_CLASS(CConnectThread),THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
if (!pThread) {
soc.Close();
return;
}
pThread->m_hSocket = soc.Detach();

pThread->ResumeThread();

CSocket::OnAccept(nErrorCode);

The SOCKET is attached in the InitInstance() and I also have a Run() which runs until a flag is set to stop it.

In the OnReceive all I have is
{
TRACE("TCP->WORKS\n");
}
I can't call SCocket::Receive() because it is saying that I can't use a non-static member function.

Any thoughts?
ScottMcP [MVP]
2013-07-02 13:09:10 UTC
Permalink
Post by Todor Atanasov
I can't call SCocket::Receive() because it is saying that I can't use a non-static member function.
How and where do you declare the CSocket in the thread class? You need a class derived from CSocket, and you need a member variable of this class in your thread class. OnReceive and Receive have to be in this CSocket-derived class.
Todor Atanasov
2013-07-02 18:52:08 UTC
Permalink
Post by ScottMcP [MVP]
Post by Todor Atanasov
I can't call SCocket::Receive() because it is saying that I can't use a non-static member function.
How and where do you declare the CSocket in the thread class? You need a class derived from CSocket, and you need a member variable of this class in your thread class. OnReceive and Receive have to be in this CSocket-derived class.
Yeah, I actually was thinking it wrong. What I do now is simply leasten inside the Run loop using the CSocket in the class. Works good for now.
Todor Atanasov
2013-07-03 11:32:31 UTC
Permalink
Post by Todor Atanasov
Post by ScottMcP [MVP]
Post by Todor Atanasov
I can't call SCocket::Receive() because it is saying that I can't use a non-static member function.
How and where do you declare the CSocket in the thread class? You need a class derived from CSocket, and you need a member variable of this class in your thread class. OnReceive and Receive have to be in this CSocket-derived class.
Yeah, I actually was thinking it wrong. What I do now is simply leasten inside the Run loop using the CSocket in the class. Works good for now.
But now for some reason the Thread Messages are not triggered.

I have ON_REGISTERED_THREAD_MESSAGE that is never called, but the PostThreadMessage returns TRUE. So what is wrong? Is it because I use Run in a infinitive loop?
ScottMcP [MVP]
2013-07-03 13:19:27 UTC
Permalink
CSocket::Listen is a blocking call, meaning it does not return until a connection request is received. So if you are calling CSocket::Listen in the thread loop then (obviously) the thread Run loop will not dispatch any messages until Listen returns.

The purpose of CSocket is to provide blocking calls. This is inherently incompatible with a thread that should also be responding to windows messages.
Todor Atanasov
2013-07-03 15:00:36 UTC
Permalink
Post by ScottMcP [MVP]
CSocket::Listen is a blocking call, meaning it does not return until a connection request is received. So if you are calling CSocket::Listen in the thread loop then (obviously) the thread Run loop will not dispatch any messages until Listen returns.
The purpose of CSocket is to provide blocking calls. This is inherently incompatible with a thread that should also be responding to windows messages.
I am not calling Listen, but Read, I am reading the socket all the time in the Run loop and doing something after a filter.
ScottMcP [MVP]
2013-07-03 16:56:04 UTC
Permalink
Same answer: While your loop is waiting in a Receive call it will not process thread messages. You should be using a class derived from CSocket and only call Receive when your class OnReceive is called. That way you will only call Read when data is available and it will always return quickly. And your thread Run loop will not be blocked.
Todor Atanasov
2013-07-03 17:15:28 UTC
Permalink
Post by ScottMcP [MVP]
Same answer: While your loop is waiting in a Receive call it will not process thread messages. You should be using a class derived from CSocket and only call Receive when your class OnReceive is called. That way you will only call Read when data is available and it will always return quickly. And your thread Run loop will not be blocked.
OK, then how to drive the class from CSocket, as it is derived from CWinThread already? :)
Todor Atanasov
2013-07-03 18:58:01 UTC
Permalink
Post by Todor Atanasov
Post by ScottMcP [MVP]
Same answer: While your loop is waiting in a Receive call it will not process thread messages. You should be using a class derived from CSocket and only call Receive when your class OnReceive is called. That way you will only call Read when data is available and it will always return quickly. And your thread Run loop will not be blocked.
OK, then how to drive the class from CSocket, as it is derived from CWinThread already? :)
So how to use the CSocket variable, if I don't use the Run()? :D
ScottMcP [MVP]
2013-07-03 21:59:36 UTC
Permalink
Create a new class derived from CSocket. Use Project, Add Class menu. For example, name it CDataSocket.

In your thread class h file, make a thread member variable of type CDataSocket.

If you have done the Detach/Attach properly:

http://support.microsoft.com/kb/175668

then the OnReceive in your CDataSocket will be called when data is available. You do not have to hook it to the Run loop: It does that all by itself.
Todor Atanasov
2013-07-04 04:28:49 UTC
Permalink
Post by ScottMcP [MVP]
Create a new class derived from CSocket. Use Project, Add Class menu. For example, name it CDataSocket.
In your thread class h file, make a thread member variable of type CDataSocket.
http://support.microsoft.com/kb/175668
then the OnReceive in your CDataSocket will be called when data is available. You do not have to hook it to the Run loop: It does that all by itself.
ScottMcP thanks a million times :D:D:D

That worked like a charm :D
Todor Atanasov
2013-07-10 06:16:45 UTC
Permalink
Post by Todor Atanasov
Post by ScottMcP [MVP]
Create a new class derived from CSocket. Use Project, Add Class menu. For example, name it CDataSocket.
In your thread class h file, make a thread member variable of type CDataSocket.
http://support.microsoft.com/kb/175668
then the OnReceive in your CDataSocket will be called when data is available. You do not have to hook it to the Run loop: It does that all by itself.
ScottMcP thanks a million times :D:D:D
That worked like a charm :D
Well I hit another underwater rock :D

No for some reason the OnReceive() stops to fire after some times (it is random, but usually around the 5-10 time). I know the socket is not close and the thread is in the client is still running, but for some reason the OnReceive is not called. I read that there might be a problem with the PumpMessage, but the client doesn't do anything else at this point then just receive and prints when there is a OnReceive (not even the data it self) just the start of the Serialization and the end of it.

Any thoughts on that problem?
Todor Atanasov
2013-07-10 09:55:41 UTC
Permalink
Post by Todor Atanasov
Post by Todor Atanasov
Post by ScottMcP [MVP]
Create a new class derived from CSocket. Use Project, Add Class menu. For example, name it CDataSocket.
In your thread class h file, make a thread member variable of type CDataSocket.
http://support.microsoft.com/kb/175668
then the OnReceive in your CDataSocket will be called when data is available. You do not have to hook it to the Run loop: It does that all by itself.
ScottMcP thanks a million times :D:D:D
That worked like a charm :D
Well I hit another underwater rock :D
No for some reason the OnReceive() stops to fire after some times (it is random, but usually around the 5-10 time). I know the socket is not close and the thread is in the client is still running, but for some reason the OnReceive is not called. I read that there might be a problem with the PumpMessage, but the client doesn't do anything else at this point then just receive and prints when there is a OnReceive (not even the data it self) just the start of the Serialization and the end of it.
Any thoughts on that problem?
I found the solution. I disable FD_READ inside the OnReceive() and then on exiting the function enable it again. :D
Found the solution here http://www.experts-exchange.com/Programming/System/Windows__Programming/MFC/Q_20545841.html
ScottMcP [MVP]
2013-07-10 19:57:38 UTC
Permalink
Calling Receive gets the data and also tells winsock to generate another FD_READ when more data is available. (FD_READ is what generates the OnReceive calls.)

If you do anything that permits the message pump to run after you call Receive then OnReceive can be reentered, before you have returned from the first OnReceive. But you don't have to disable FD_READ to fix that: Just return from OnReceive without doing anything that allows the message pump to run. (For example, do not call MessageBox.)
Todor Atanasov
2013-07-11 13:11:14 UTC
Permalink
Post by ScottMcP [MVP]
Calling Receive gets the data and also tells winsock to generate another FD_READ when more data is available. (FD_READ is what generates the OnReceive calls.)
If you do anything that permits the message pump to run after you call Receive then OnReceive can be reentered, before you have returned from the first OnReceive. But you don't have to disable FD_READ to fix that: Just return from OnReceive without doing anything that allows the message pump to run. (For example, do not call MessageBox.)
Any ideas how to check if the socket is still alive, I am sending data very second, and when the client drops for some reason (manual close, line disconnected and so on) the .Flush fails with exception. Can I have a safe guard of some sort?
Loading...