先贴出我线程的部分代码:
while (WAIT_OBJECT_0 != WaitForSingleObject(piocp->m_hShutDown, 0))
{
//从完成队列中读取消息
LVB_IOCPStatus = GetQueuedCompletionStatus(piocp->m_hIOCP, &LVI_TransByte, 
(PULONG_PTR)&pSocketContext, &poverlapped, INFINITE);
//当完成端口出错时,返回值为0
if (!LVB_IOCPStatus)
{
//错误分两种,1、Overlapped为空;2、Overlapped不为空,详见MSDN
int iError = WSAGetLastError();
if (poverlapped)
{
if (!piocp->mFB_HandleError(pSocketContext, iError))
break;//完成端口出错,则退出该线程
}
continue;
}
else
        {
          //处理客户端请求
        }
}
问题:假如现在A线程在给client发送文件,但还没发送完成,此时client断开了连接,则按成端口会收到两个通知(这句话对么?),一个通知是客户端断开连接,假设是由线程B接收该通知,用wsagetlasterror()返回64,另一个通知是线程A反馈的发送文件错误。问题来了,假如B先收到通知,则他会删除该连接,之后A收到了发送文件错误的通知,此时该连接已经删除了,那么该如何处理?完成端口多线程同步

解决方案 »

  1.   

    client先发送操作类型,告诉服务器,我要下载文件了,服务端接到通知后(由完成端口接收),开始执行发送文件的函数(用transmitfile发送),待该函数返回后,继续投递接收,这样的话我是收到两个通知,与你说的也相符,那对于这两个通知,我要怎么处理连接被删除之后的那个通知呢?
      

  2.   

    client先发送操作类型,告诉服务器,我要下载文件了,服务端接到通知后(由完成端口接收),开始执行发送文件的函数(用transmitfile发送),待该函数返回后,继续投递接收,这样的话我是收到两个通知,与你说的也相符,那对于这两个通知,我要怎么处理连接被删除之后的那个通知呢? 
      

  3.   

    都被删除了 后面那个通知还需要做什么操作呢?  client断了 所有投递操作都返回失败  程序处理失败只要处理一次的吧  后面的操作除非有对应的内存释放等  否则都不用管了
      

  4.   

    关键在lpCompletionKey。如果每个新连接你都new一个 PER_HANDLE_CONTEXT,那么有可能出现野指针。这是因为当对面关闭套接字,而在队列中的投递数量大于2时,你一方面得关闭套接字释放资源,另一方面对于除第一个以外的投递没法处理。所以,你必须对lpCompletionKey中存储的内容做工作。
    给你一些思路,供你参考。第一种思路:
    1、固定最大连接数(如1000),事先建立好套接字数组。(也可以是结构体数组)
    2、在lpCompletionKey中存放SOCKET值或者数组索引。
    3、当紧急关闭时,第一个投递当然做关闭socket和释放资源,第二个以后的投递,可以根据 socket==INVALID_SOCKET 来判断和进行错误处理。
    4、当然,上面的操作涉及资源竞争,加锁是必须的。第二种思路:
    1、不固定最大连接数,连接后 new 一个 PER_HANDLE_CONTEXT,但这个结构体内部应具有对所有该Socket上的IO操作的记录,可以用计数器或链表。“完成端口是FIFO,有进必然有出。”当所有的进出操作都记录在案后,那么何时该关闭套接字和释放资源,你就知道了。
    2、上面的操作同样需要用锁,而且用量较大,但程序是稳定的。
    3、另外,提醒你虽然完成端口是FIFO,但是线程池调度是LIFO。这一点你一定要清楚,别因为通告顺序干扰了你的思路。
    以上仅是思路,要想做好完成端口,这些肯定是不够的。我也只能帮到这里了。
      

  5.   


    谢谢你的回复,我所反馈的问题正如你所说的那样。那这样的话,就只能是最后一次接到完成通知时,才释放资源,之前的操作才不会非法。 我发送文件是在线程函数里调用了transmitfile来发送,我只启动一个线程时,文件发送是没问题的,但是启
    动多个线程来接收完成端口通知,则会出现发送失败的现象。
    我的操作流程是这样的
    1、client发送下载请求
    2、server收到请求后,唤醒线程A,然后A调用transmitfile发送文件
    3、client通过多次recv和writefile接收文件
    4、当发送完成,server端完成端口接到完成通知,释放资源
      

  6.   

    问题解决了,非常感谢“Squall_zy”和“yaozhiyong110”提供的思路,是我自己理解错了,现在改为每次只投递一个操作,这样就保证了接收通知的顺序。 结贴!