CSocket在多线程里的编程,高手请进,内附程序!!!!!!!!!!

mygoodday 2003-01-13 04:27:05
可执行环境是一个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 handlers

BOOL 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();

}

...全文
48 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
icelight 2003-01-16
  • 打赏
  • 举报
回复
在多线程中使用SOCKET API不会出错,会出错的是微软的CSocket类。

你可以任意传递任何SOCKET句柄到任意线程而不会出错(记得closehandle(hSocket))。

千万千万不要冤枉SOCKET API。
fantong 2003-01-16
  • 打赏
  • 举报
回复
这个问题微软早就公布解决方法了,在多线程中使用socket会导致出错
你跟踪会发现是在lookuphandle出错
解决办法:在每个使用socket的线程一开始调用AfxSocketInit,要使用别的线程的socket要先detach,要用的attach
everandforever(Forever)已经给出解决办法了
具体参见Q193101(查msdn)
sjzxyg 2003-01-15
  • 打赏
  • 举报
回复
将socket句柄传进去,而不要传对象指针
zj510 2003-01-15
  • 打赏
  • 举报
回复
CSOCKET对多线程的支持是出了名的不好。
如果你一定要用多线程,建议SOCKET API。
虽说烦了点,但是典型的代码网上多的是,你靠过来就可以了。
mygoodday 2003-01-15
  • 打赏
  • 举报
回复
现在发现一个新问题,
在多线程中启动的SOCKET只能发,而不能接受。
请问是怎么回事?????????
mygoodday 2003-01-15
  • 打赏
  • 举报
回复
网址也可!!!
mygoodday 2003-01-15
  • 打赏
  • 举报
回复
请楼上的各位高手,可否将例子发给我,急急急急!!
flycloud2002@hotmail.com
everandforever 2003-01-15
  • 打赏
  • 举报
回复
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);
...
}
CoolBoy_007 2003-01-15
  • 打赏
  • 举报
回复
Socket 传送要通过它的Attach方法传递最为安全,然后将原来的socket对象Detach方法释放SOCKET句柄,这样最合理!
m_pDelphi 2003-01-14
  • 打赏
  • 举报
回复
socket 最好不要跨线程,否则要对消息进行处理,SOCKET的通信是以线程为单位的,是一个线程与另一个线程的通信,你把线程中对SOCKET的操作拿到你的主进程中去,肯定就不会错了,如果你一定要放在线程中,加上
MSG msg;
if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (GetMessage(&msg, NULL, 0, 0 ) != -1)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
这样的消息派送代码
zzyx 2003-01-14
  • 打赏
  • 举报
回复
代码
hThrds=CreateThread(NULL,0,SocketThread,(LPVOID)(this),0,NULL);
是要向另外一个线程传递一个MFC的窗体对象,非常典型的错误。
看以前的帖子吧,对这个问题将的比较多了。

free_card 2003-01-14
  • 打赏
  • 举报
回复
up

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧