使用CSokcet和CWinThread,线程中的PostMessage不起作用

时间:2016-05-13 13:49:31

标签: c++ multithreading mfc network-programming

我正在network programming上学习MFC,并在这里引用了比目鱼的指南:http://www.flounder.com/kb192570.htm来搞乱多线程和套接字。但我的工作更简单。

我想要做的是制作一个多线程服务器客户端模型。服务器只是坐着听,而客户端telnet到它。一旦有连接,服务器将创建线程来处理OnAccept()中的连接。在创建时,线程将PostMessage及其主线GUI的线程ID。然后GUI使用函数处理该消息,以弹出MessageBox以显示线程ID。就这么简单。

我的问题是:尽管成功制作了线程,依赖套接字句柄(我已在netstat上检查过),但线程的通知消息从未发送到GUI。

这是我的代码:
CListenSocket.hCConnectSocket.h在.h中非常相同(源自CSocket

......
public:   
//Handle CWnd pointer from main GUI
   void SetParrent(CWnd * w) { windowsParrent = w; }
   CWnd * GetParrent() { return windowsParrent; }
protected:
   CWnd *windowsParrent;
.......
};

CClientThread.h(源自CWinThread

....
public:
   void SetParrent(CWnd * w) { windowsParrent = w; }
   CWnd * GetParrent() { return windowsParrent; }

   SOCKET handleThreadSocket;
   CConnectedSocket threadSocket;
protected:
   CWnd *windowsParrent;
....

现在,当我创建listen套接字时,我已经将GUI的CWnd指针传递给它:

CListenSocket m_Listener;
....
m_Listener.SetParrent(this);
m_Listener.Create(1001);    
m_Listener.Listen();

然后OnAccept()创建了CListenSocket线程,但我没有忘记传递CWnd指针......

void CListenSocket::OnAccept(int nErrorCode)
{
   if(nErrorCode != 0)
   {
       CSocket temp_soc;
       CClientThread *pThr = (CClientThread*)AfxBeginThread(
                                            RUNTIME_CLASS(CClientThread),
                                            THREAD_PRIORITY_NORMAL,
                                            0,
                                            CREATE_SUSPENDED);

       pThr->SetParrent(windowsParrent);           
       pThr->handleThreadSocket = temp_soc.Detach();
       pThr->ResumeThread();
   }    
   CSocket::OnAccept(nErrorCode);
}

CThreadClient.cpp:线程创建

BOOL CClientThread::InitInstance()
{
   threadSocket.Attach(handleThreadSocket); 
   if (threadSocket == NULL)
   {
    return FALSE;
   }    
   if (windowsParrent == NULL)
   {
       return FALSE;
   }
   windowsParrent->PostMessage(THREAD_STARTED,0,(LPARAM)m_nThreadID);
   return TRUE;
}

最后,我使用函数映射THREAD_STARTED只是为了做这件事:

LRESULT CServerSideDlg::OnThreadStart( WPARAM, LPARAM lparam )
{
   UpdateData(TRUE);
   DWORD ThreadID = (DWORD)lparam;
   CString echo;
   echo.Format("%d",ThreadID);     
   UpdateData(FALSE);
   AfxMessageBox("Thread stated: "+echo);
   return 0;
}

以下是映射:

BEGIN_MESSAGE_MAP(CServerSideDlg, CDialog)
...
//}}AFX_MSG_MAP
ON_MESSAGE (THREAD_STARTED, OnThreadStart)
END_MESSAGE_MAP()

线程工作,连接套接字也有效,但没有消息已经发布。请帮忙,我哪里错了。提前谢谢。

1 个答案:

答案 0 :(得分:0)

我找到了解决这个问题的方法,但我仍然不知道为什么我以前的工作没有按照我的预期工作。

我将CListenSocket.h更改为:

public:
void SetParentDlg(CDialog *pDlg) {parrentDlg = pDlg;}
....
protected:
CDialog *parrentDlg;

所以我要做的不是将CWnd存储在套接字中,而是将CDialog存储在GUI中。现在当我创建socket时:

m_Listener.Create(1001);    
m_Listener.Listen();
m_Listener.SetParentDlg(this);

通过这样做,我可以将套接字OnAccept()覆盖到主GUI上的函数:

void CListenSocket::OnAccept(int nErrorCode)
{
if(nErrorCode == 0)
{
    ((CServerSideDlg*)parrentDlg)->OnAccept(); //Here I use the function OnAccept() from GUI to handle accepted connections.
}   
CSocket::OnAccept(nErrorCode);
}

然后在我的Dlg上,我只创建一个公共方法OnAccept()来创建线程并将CWnd传递给线程。

void CServerSideDlg::OnAccept()
{

   CSocket temp_soc;
   if (m_Listener.Accept(temp_soc))
   {
    CClientThread *pThr = (CClientThread*)AfxBeginThread(
                                        RUNTIME_CLASS(CClientThread),
                                        THREAD_PRIORITY_NORMAL,
                                        0,
                                        CREATE_SUSPENDED);

   pThr->SetParrent(this);         //pass CWnd to thread  
   pThr->handleThreadSocket = temp_soc.Detach();
   pThr->ResumeThread();
   }
}

其余的没有改变,而且有效。

那么,为什么我不能将CWnd从GUI传递到套接字然后传递给线程呢?我只能将它从GUI传递给线程......请问有什么想法吗?