MFC之旅——CSocket神级易错点

CSocket是对底层winsock32的api的封装,实现对象型。方便我们的网络MFC程序的编写。

这个类的使用大家很可能会忽视一点。导致一个很难受的报错。

我的经历就是两个字:难受。

易错点一

写MFC网络程序时,一般都是需要使用多线程的。我在无聊编写一个聊天软件时。就出现了这样的一个报错。(VS2017 & win7 64)

 BOOL CSocket::PumpMessages(UINT uStopFlag)
{
	// The same socket better not be blocking in more than one place.
	ASSERT(m_pbBlocking == NULL);

	_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;

	ASSERT(pState->m_hSocketWindow != NULL);

	BOOL bBlocking = TRUE;
	m_pbBlocking = &bBlocking;
	CWinThread* pThread = AfxGetThread();

在这里会引发一个断点。但是把代码放在我的主线程下运行就不会有问题。

引起这个断点的错误原因,多半就是,你并没有在这个新建立的线程里面调用AfxSocketInit()初始化socket....

这个错误我在学习MFC的socket时,在MFC中看到过。但是,在实际编写过程中,我还是犯错了。所以这说明,你学过的知识,没有运用。你是不会正真的记住。


易错点二

在进行多线程网络编程时,难免通信的处理要转移给另一个线程去执行。我很自然的会想到直接把。这个CSocket对象地址传给另一个线程去调用,不就可以了?然而,实际上我这样写了。却出现了错误。后来经过网上查找资料,找到了这样一篇博客。

下面附上链接:跨线程使用CSocket

这位作者详细的讲述了他寻找原因的过程,希望对大家有帮助,我的理解是,为了保护线程的网络通信安全。于是MFC内部的CSocket会在一个CSocket创建后。将当前线程ID存储在一个成员变量内部,当然,应该是非public。在其他线程中调用此CSocket的成员函数时,验证线程ID,如果不同,就会抛出异常。

Remark:这里需要注意的是,在我实际编写中发现,并不是所有的成员函数都会进行验证。比如我调用SendTo()这个函数就算是跨线程也能正常执行。但是ReceiveFrom()就不行了。这就很奇怪了。为什么只保护接收,而不保护发送。


跨线程时的解决办(引用自上面那篇博客):既然CSocket绑定在了线程上,那么就帮CSocket更换一个绑定对象。在原线程中调用其成员函数SOCKET CSocket::Detach();解除对象与SOCKET的绑定。然后把SOCKET传入另一个线程中,在其中调用BOOL CSocket::Attach(SOCKET socket)进行绑定。这样就把这个SOCKET绑定到这属于这个线程的一个CSocket对象上了。

不知道大家发现没,这个非常像互斥对象。一个线程在使用时,其他线程就无法调用。必须让原线程调用Detach放弃使用权。另一个线程才能Attach获取使用权。所以,如果这个线程不用了,要把使用权给其他线程时,也要记得调用Detach哦,这是在编写程序中特别要注意的。不然,BUG会带走你的快乐哦!



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值