csocket 相关3

没有做过Socket编程,近来在项目中增加一个网络模块时与Socket短兵相接!
正如所料,遇到了不少问题,但是都很快就得到了解决,现在网络时代搜索引擎是利器啊!
可是最近测试程序的时候发现服务端频繁的当掉,经过debug调试发现是在
CSocket::PumpMessages(UINT uStopFlag)函数中的
ASSERT(pState->m_hSocketWindow != NULL);语句出现了问题,
查看调用堆栈发现CSocket::SendChunk()调用了PumpMessages()函数;
CSocket::Send()调用了SendChunk()函数,看来是在发送数据时出现的问题。
于是在Send函数后做了返回值检查,当返回小于发送值或为SOCKET_ERROR时中断处理;
结果函数未返回就发生了错误!看来还得仔细跟踪一下程序的脚步……

CSocket::Send()和SendChunk()只是对CAsyncSocket::Send做了一些同步处理的封装;
在SendChunk()中当调用CAsyncSocket::Send()返回WSAEWOULDBLOCK错误时才会
执行PumpMessages(FD_WRITE);WSAEWOULDBLOCK错误的原因是忙,输出缓冲已满;
我试着将客户端接收加了Sleep(500),果然增加了出错的概率。
而将服务端Send前增加了延时,出错概率少了,但是发送一段时间就会出错。
实际系统运行过程中将面对性能不确定的客户端,就是说不能保证客户端会及时接收数据,
所以在服务端使用Sleep()只能减少出错,但是无法从根本解决问题!

看来问题的起源搞清楚了,由于客户端不能及时地接收数据,使得服务端缓冲溢满,
从而导致Send函数阻塞于是执行PumpMessages(FD_WRITE)函数等待可写消息的到来!
可是这种情况很常见的,为什么会引起服务端出现异常呢?
进入PumpMessages()函数到出错仅仅两行代码:
_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
ASSERT(pState->m_hSocketWindow != NULL);
经过查询得知_AFX_SOCK_THREAD_STATE是当前的模块线程状态,
而m_ hSocketWindow是本模块在当前线程的“socket窗口”,
现在因为pState->m_hSocketWindow为NULL而出现断言失败!为什么会断言失败呢?

于是经过长时间的艰苦搜索,终于得知MFC的 CSocket类是线程不安全的,
就是说跨线程使用CSocket会造成很多问题,这不这就是跨线程的结果!
我在主线程种创建了CSocket对象,在新的线程中调用其Send函数,正常的情况下没问题,
但是当涉及到一些CSocket相关且线程相关的对象时就会导致得不到对象而出错。

问题似乎搞明白了,可是如何解决呢!代码已经写了一大堆,原先想使用MFC现成的
类,省了从API写起。现在看来似乎不是想得那么容易啊!

于是搜索CSocket跨线程的技巧,搜到一个方法是微软提供的,看来微软也意识到了这个缺陷!
就是使用Detach()和Attach(),在线程中传递SOCKET句柄而不是MFC对象指针。
于是很快代码改造完毕,在新线程中还得调用一下AfxSocketInit()。
经过测试在新线程倒是可以工作,但是主线程将不能够接收客户端发送过来的其他消息,
新线程只是个工作线程,循环发送数据,直到客户端发送停止指令。现在的情况是客户端
发送停止指令在服务端得不到任何响应,看来这还不是个办法!我累……,不过挺有意思,
就像一个侦探在层层剥离一个谜团,真相将渐渐显现……!


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值