可执行环境是一个CDialog程序
在多线程里创建CSocket对象,并连接到某一个服务器。
当调用OnButtonDelete函数时,到m_pSocket->Close();就出错???
具体是
BOOL CAsyncSocket::AsyncSelect(long lEvent)
{
ASSERT(m_hSocket != INVALID_SOCKET); _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
ASSERT(pState->m_hSocketWindow != NULL);//出错 return WSAAsyncSelect(m_hSocket, pState->m_hSocketWindow,
WM_SOCKET_NOTIFY, lEvent) != SOCKET_ERROR;
}
程序代码如下:
其中CSocketTest类是派生自CSocket;只是在close()里设置TestMutipleSocketDlg类的m_bConnect=FALSE;其他都不做
头文件为:
// TestMutipleSocketDlg.h : header file
class CTestMutipleSocketDlg : public CDialog
{
public:
CMutex m_Mutex;
CSocketTest *m_pSocket;
public:
int m_iPort;
BOOL m_bEndThread;
BOOL m_bConnect;
BOOL StartSocket();
CTestMutipleSocketDlg(CWnd* pParent = NULL); // standard protected:
HICON m_hIcon; // Generated message map functions
//{{AFX_MSG(CTestMutipleSocketDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButtonConnect();
afx_msg void OnButtonClose();
afx_msg void OnButtonDelete();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
DWORD WINAPI SocketThread(LPVOID pParam);实现文件为:
// TestMutipleSocketDlg.cpp : implementation file
#include "stdafx.h"
#include "TestMutipleSocket.h"
#include "TestMutipleSocketDlg.h"
#include "SocketTest.h"// CTestMutipleSocketDlg dialog
CTestMutipleSocketDlg::CTestMutipleSocketDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTestMutipleSocketDlg::IDD, pParent)
{
m_iPort=8776;
m_bEndThread=FALSE;
m_pSocket=NULL;
m_bConnect=FALSE;
//{{AFX_DATA_INIT(CTestMutipleSocketDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}void CTestMutipleSocketDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTestMutipleSocketDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}BEGIN_MESSAGE_MAP(CTestMutipleSocketDlg, CDialog)
//{{AFX_MSG_MAP(CTestMutipleSocketDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_CONNECT, OnButtonConnect)
ON_BN_CLICKED(IDC_BUTTON_CLOSE, OnButtonClose)
ON_BN_CLICKED(IDC_BUTTON_DELETE, OnButtonDelete)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
// CTestMutipleSocketDlg message handlersBOOL CTestMutipleSocketDlg::OnInitDialog()
{
CDialog::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
return TRUE;  // return TRUE  unless you set the focus to a control
}void CTestMutipleSocketDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
void CTestMutipleSocketDlg::OnPaint() 
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTestMutipleSocketDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
DWORD WINAPI SocketThread(LPVOID pParam)
{
CTestMutipleSocketDlg *pSocketDlg=(CTestMutipleSocketDlg*)pParam;
while(pSocketDlg->m_bEndThread==FALSE)
{
//if(pSocketDlg->m_bConnect==FALSE)
{
CSingleLock slock(&pSocketDlg->m_Mutex);
slock.Lock();
       pSocketDlg->StartSocket();
slock.Unlock();
       Sleep(2000);
}
}
return 0;
}void CTestMutipleSocketDlg::OnButtonConnect() 
{
// TODO: Add your control notification handler code here
HANDLE hThrds;
// StartSocket();
hThrds=CreateThread(NULL,0,SocketThread,(LPVOID)(this),0,NULL);
}BOOL CTestMutipleSocketDlg::StartSocket()
{
if(m_pSocket!=NULL)
{
    m_pSocket->ShutDown();
//
m_pSocket->Close();//
delete m_pSocket;
m_pSocket=NULL;
}
Sleep(3000);
m_pSocket=new CSocketTest(this);
if(!m_pSocket->Create())
{
this->SetWindowText("socket创建失败");
delete m_pSocket;
m_pSocket=NULL;
return FALSE;

}
if(!m_pSocket->Connect("127.0.0.1",m_iPort))
{
TRACE("Connect Server Error");
this->SetWindowText("服务器断开");
delete m_pSocket;
m_pSocket=NULL;
return FALSE;
}
m_bConnect=TRUE;
return TRUE;
}void CTestMutipleSocketDlg::OnButtonClose() 
{
// TODO: Add your control notification handler code here
m_pSocket->Close();
}void CTestMutipleSocketDlg::OnButtonDelete() 
{
// TODO: Add your control notification handler code here
CSingleLock slock(&m_Mutex);
slock.Lock(); if(m_pSocket!=NULL)
{
m_pSocket->ShutDown();
m_pSocket->Close();
delete m_pSocket;
m_pSocket=NULL;
}
slock.Unlock();}

解决方案 »

  1.   

    代码 
    hThrds=CreateThread(NULL,0,SocketThread,(LPVOID)(this),0,NULL);
    是要向另外一个线程传递一个MFC的窗体对象,非常典型的错误。
    看以前的帖子吧,对这个问题将的比较多了。
      

  2.   

    socket 最好不要跨线程,否则要对消息进行处理,SOCKET的通信是以线程为单位的,是一个线程与另一个线程的通信,你把线程中对SOCKET的操作拿到你的主进程中去,肯定就不会错了,如果你一定要放在线程中,加上
    MSG msg;
    if(PeekMessage(&msg, NULL,  0, 0, PM_NOREMOVE))
    {
    if (GetMessage(&msg, NULL, 0, 0 ) != -1)
    {
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
    }
    }
    这样的消息派送代码
      

  3.   

    CSOCKET对多线程的支持是出了名的不好。
    如果你一定要用多线程,建议SOCKET API。
    虽说烦了点,但是典型的代码网上多的是,你靠过来就可以了。
      

  4.   

    将socket句柄传进去,而不要传对象指针
      

  5.   

    Socket 传送要通过它的Attach方法传递最为安全,然后将原来的socket对象Detach方法释放SOCKET句柄,这样最合理!
      

  6.   

    void CESocket::OnAccept(int nErrorCode)
    {
    if (nErrorCode == 0)
    {
    Accept(m_AcceptSocket);
    m_pEThread = new CEThread(m_AcceptSocket.m_hSocket);
    m_pEThread->CreateThread();
    m_AcceptSocket.Detach();
    ...
    }CEThread::CEThread(SOCKET sock)
    {
    m_hSock     = sock;
    ...
    }
    BOOL CEThread::InitInstance()
    {
    m_Socket.Attach(m_hSock);
    ...
    }
      

  7.   

    请楼上的各位高手,可否将例子发给我,急急急急!!
    [email protected]
      

  8.   

    现在发现一个新问题,
    在多线程中启动的SOCKET只能发,而不能接受。
    请问是怎么回事?????????
      

  9.   

    这个问题微软早就公布解决方法了,在多线程中使用socket会导致出错
    你跟踪会发现是在lookuphandle出错
    解决办法:在每个使用socket的线程一开始调用AfxSocketInit,要使用别的线程的socket要先detach,要用的attach
    everandforever(Forever)已经给出解决办法了
    具体参见Q193101(查msdn)
      

  10.   

    在多线程中使用SOCKET API不会出错,会出错的是微软的CSocket类。你可以任意传递任何SOCKET句柄到任意线程而不会出错(记得closehandle(hSocket))。千万千万不要冤枉SOCKET API。