各位大侠:我写的服务器遇到一个这样的问题;
1.我在发送数据的时候,在打好数据包后我用PostQueuedCompletionStatus通知工作线程处理发送消息。
2.工作线程接收到消息,将步骤1中写入队列的数据buffer取出, 并调用WSASend写数据包到发送缓存。即调用我的OnSendBegin函数。
3.接着,完成端口接收到响应--缓冲数据发送完成消息,同时我会在此时释放从队列中取出的缓存buffer。即调用我的OnSendEnd函数。但就是在这个流程中,如果我在接收到一条数据后,连续的向Client直接进行发送多条数据(我测试的是5条)。然后我强行断掉client端(就在这种情况下才出现),这时候会出现OSendBegin与OnSendEnd的发送前,与发送后的次数不一致(这时我是不关闭socket的,服务器会一直等待,OSendBegin投递的数据都被OnSendEnd执行完成后才关闭socket)。但发现会出现两种情况:
1)OnSendBegin的执行次数比OnSendEnd执行次数多一次。也就是OnSendBegin执行了n,但OnSendEnd执行n-1次,而造成内存池中的一块内存不被释放。(这个频繁出现)
2)OnSendEnd的执行次数比OnSendBegin执行次数多一次。也就是OnSendEnd执行了n,但OnSendBegin执行n-1次,而造成内存池中的一块内存计数被释放两次。(这个出现但不频繁)为什么呢?完成端口为什么没有或多投递OnSendEnd呢?我没有清除Socket的缓存也没有关闭Socket啊。这种情况如何解决呢?

解决方案 »

  1.   

    感觉你的程序结构有一个问题,为什么要让PostQueuedCompletionStatus来通知工作线程呢?直接WSASend,就相当于投递了一个PostQueuedCompletionStatus加一个WSASend,你现在正好反着的,另外你需要判断WSASend是否成功,如果本身发送失败,完成端口是不会有消息的,所以如果你的OnSendEnd是从完成端口得到消息,在这种情况下,2个次数就是不等的。
      

  2.   

    其实我当时也考虑过,是想将所有的投递与发送等socket事务处理都放到WorkThread,另外开辟的线程来做业务处理的。从我的角度来看,其实我只是更换了一下Send的处理线程池的位置,按道理应该不会有问题的。
      

  3.   

    逻辑是没有多大问题,你要保证每次WSASend没有返回SOCKET_ERROR,有这个错误的话,完成端口是没有消息的,也就没有你的
    OnSendEnd
      

  4.   

    如果用完成端口我只记SendMsg,而不放到链表中做序列化的话,会不会有问题呢?我之所以那样做的另外一个原因就是,想做所有client发送消息的序列化。
      

  5.   

    現在我也遇到這個問題了。我是做一個 臨界區。要發送數據時,先進臨界區。如果 m_Sending = true 表示有數據正在發送中,這時就只需要把數據加到List 中就可以了。而在 WorkThread 中,得到發送完成事件,我也先進臨界區,如果 List 為空,那把我 m_sending = false; 退出。如果 list 不為空,就把第一個包讀出來,發送。退出臨界區
    .....
      

  6.   


    如果你在断开client端时,OnSendBegin()被执行了,但数据还是在系统缓冲中,还没有全部发送到client端的话,你的第三步自然没有被执行到(因为没有完全发送完毕的消息,OnSendEnd()自然就没被执行到),那么OnSendEnd比OnSendBegin少一次并不是奇怪事.