Reputation: 177
I am new to MFC's CWinThread
and CAsyncSocket
, and trying to learn them myself with dialog based application.
Here is what I want to do: make a server/multi-client model: when the number clients connect to server, the server will make threads according to the number of clients and passes the socket connecting to the thread. I have refereed this article to do the passing: https://support.microsoft.com/en-us/kb/175668 .
I have successfully make thread on every connection, but...
My question is: Can I from the main windows(GUI) re-access all sockets that have been passed to threads to send(broadcast) data to all the clients?
This is how I do the passing:
On server side:
void CMyServerDlg::OnAccept(){
CConnectSoc temp_soc;
m_Listener.Accept(temp_soc);
CSocketThread *pThr = (CSocketThread*)AfxBeginThread(
RUNTIME_CLASS(CSocketThread),
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
pThr->threadHandleSocket = temp_soc.Detach();
pThr->ResumeThread();
}
Note: m_Listener
is the object of the class that derived from CAsyncSocket
and CSocketThread
is derived from CWinThread
.
Inside the thread header, I added 2 lines:
Public:
CConnectSoc threadSocket;
SOCKET threadHandleSocket;
Inside the thread class .cpp:
BOOL CSocketThread::InitInstance(){
threadSocket.Attach(threadHandleSocket);
return TRUE;
}
Can someone tell me what to do next to send data to those socket?
Upvotes: 0
Views: 528
Reputation: 177
After some research, I finally think I can answer my own question, thanks for your help; but please fix me, if there is a better solution or mine is not a good practice.
MY SOLUTION:
The key word here is PostMessage()
and PostThreadMessage()
. We must make the communication between the GUI and the Threads. However, the problem is the thread cannot call PostMessage()
which is a member function of CWnd
to send message to the GUI (I have no idea why not). So I need a pointer in the thread class to point to the CWnd from the GUI:
In header of the thread class:
public:
CWnd *wParrent;
Then at the stage of creating thread, I just have to add 1 line:
void CMyServerDlg::OnAccept(){
CConnectSoc temp_soc;
m_Listener.Accept(temp_soc);
CSocketThread *pThr = (CSocketThread*)AfxBeginThread(
RUNTIME_CLASS(CSocketThread),
THREAD_PRIORITY_NORMAL,
0,
CREATE_SUSPENDED);
pThr->wParrent = this; //<== this line
pThr->threadHandleSocket = temp_soc.Detach();
pThr->ResumeThread();
}
By doing this, I can now post message from the thread to give the GUI my thread's ID.
In the thread .cpp:
BOOL CSocketThread::InitInstance(){
threadSocket.Attach(threadHandleSocket);
wParrent->PostMessage(THREAD_STARTED, 0, (LPARAM)m_nThreadID);
return TRUE;
}
Then at GUI: we handle message THREAD_STARTED
with a function to store m_nThreadID
for future use:
Somewhere in Dlg header:
CDWordArray m_threadIDs;
Dlg .cpp
LRESULT CMyServer3Dlg::OnThreadStart(WPARAM, LPARAM lParam){
DWORD ThreadID = (DWORD)lParam;
m_threadIDs.Add(ThreadID);
return 0;
}
When sending data to all clients, use PostThreadMessage()
in a loop through m_ThreadIDs
:
for (int i =0; i<m_threadIDs.GetCount(); ++i){
PostThreadMessage(m_threadIDs[i],SEND_DATA,(WPARAM)bufferSize,(LPARAM)socketBuffer);
}
Handle SEND_DATA
message in the thread with a function to do the sending:
In thread .cpp:
void CSocketThread::SendDataFunc(WPARAM wParam, LPARAM lParam){
ASSERT(threadSocket != NULL);
if(threadSocket == NULL)
{
return;
}
else
{
char *socketBuffer = (char*)lParam;
int bufferSize = (int)wParam;
send(threadSocket, socketBuffer, bufferSize, 0);
}
That's what I have done, and no problem so far....
Upvotes: 1