Chapter 6, Listing 6-4
IssueRead 函数在 接受客户端连接后,然后 创建客户端套接字,将该套接字关联完成端口后, 就调用它。调用它的本意是: 投递请求接受数据。 这里没有用WSARecv,而是用ReadFile.           看代码void IssueRead(struct ContextKey *pCntx)
{
    int     i = 0;
    BOOL    bResult;
    int     err;
    int     numRead;    while (++i)
    {
        // Request a single character
        bResult = ReadFile(
                    (HANDLE)pCntx->sock,
                    pCntx->InBuffer,
                    1,
                    &numRead,
                    &pCntx->ovIn
                );        // It succeeded immediately, but do not process it
        // here, wait for the completion packet.
        if (bResult)
            return;        err = GetLastError();        // This is what we want to happen, it's not an error
        if (err == ERROR_IO_PENDING)
            return;        // Handle recoverable error
        if ( err == ERROR_INVALID_USER_BUFFER ||
             err == ERROR_NOT_ENOUGH_QUOTA ||
             err == ERROR_NOT_ENOUGH_MEMORY )
        {
            if (i == 5) // I just picked a number
            {
                Sleep(50);  // Wait around and try later
                continue;
            }            FatalError("IssueRead - System ran out of non-paged space");
        }        break;
    }    fprintf(stderr, "IssueRead - ReadFile failed.\n");
}
如果同步收到数据的,那么ReadFile必然返回true,所以立即返回, 然后去接受线程中接受数据(通过GetQueuedCompletionStatus)如果没有接受完成,那么返回 ERROR_IO_PENDING,  也可以返回,反正接受线程也可以拿到数据。第三种情形:发生了其他错误。ERROR_INVALID_USER_BUFFER    ERROR_NOT_ENOUGH_MEMORY The ReadFile function may fail with ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding asynchronous I/O requests.
这些错误时可以修复的?  
显然是不可修复的,所以是作者的第一个错误!还有个错误:  if ( err == ERROR_INVALID_USER_BUFFER ||
             err == ERROR_NOT_ENOUGH_QUOTA ||
             err == ERROR_NOT_ENOUGH_MEMORY )
        {
            if (i == 5) // I just picked a number
            {
                Sleep(50);  // Wait around and try later
                continue;
            }            FatalError("IssueRead - System ran out of non-paged space");
        }i==5?  搞笑吧, 这个函数里的循环无论怎么执行, 一次就跳出了,   怎么可能i==5?
这个函数就2个错误。
第三个错误:
    // calloc will zero the buffer
        pKey = calloc(1, sizeof(struct ContextKey));
        pKey->sock = newsocket;
        pKey->ovOut.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        // Set the event for writing so that packets
        // will not be sent to the completion port when
        // a write finishes.
        pKey->ovOut.hEvent = (HANDLE)((DWORD)pKey->ovOut.hEvent | 0x1);        // Associate the socket with the completion port
        CreateIoCompletionPort(
                (HANDLE)newsocket,
                ghCompletionPort,
                (DWORD)pKey,   // No key
                0              // Use default # of threads
            );        // Kick off the first read
        IssueRead(pKey);作者为了实现所谓的 防止受到客户端的数据后, 服务端会偷偷的发送一个 封包给完成端口, 为了减少完成端口的压力,所以作者采用了,一个法子,使用了WSAEvent, 注意: 如果事件有信号后,没有WSAResetEvetn啊?需不需要,  我查了不少资料,不知道这个法子,作者是从哪里搞来的。  

解决方案 »

  1.   

    1当前错误不可恢复,然后cotinue进行下一次的尝试。
    2是表明这个socket不加入IO队列(创建一个Event,然后 (句柄| 0x01)),这个在windows 核心编程中提及。
      

  2.   

    能否普及一下,  如果socket不放在io队列中会如何?事件是否需要WSAResetEvent?还有: 我查过msdn,   那几个错误是不可恢复的, 不可恢复, 与i==5 根本无关,可以直接continue啊, 是不?
      

  3.   

    开始时i == 0,在你发现错误时:
            // Handle recoverable error
            if ( err == ERROR_INVALID_USER_BUFFER ||
                 err == ERROR_NOT_ENOUGH_QUOTA ||
                 err == ERROR_NOT_ENOUGH_MEMORY )
            {
                if (i == 5) // I just picked a number
                {
                    Sleep(50);  // Wait around and try later
                    continue;
                }i显然小于5,然后就continue,下面的语句就忽略了。为了保险,这里还sleep(50),呢,应该没大问题。
    不加入io队列(这个说法不严谨,应该是iocp队列),就表明不使用iocp呀,查下书吧,可能是同步的方式。搞这个得看书呢,记得不太清了。
      

  4.   

    ReadFile完全正确只是你不懂而已。。
      

  5.   

    嗯,来源于 unix,凡事皆文件。
      

  6.   


    你说的不对,直接break了, 永远不会执行i==5,所以不存在continue!!
    第二: 作者也和提到过  WSACreateEvent后的句柄,然后将该句柄和 1进行 或操作, 再次复制给该句柄,我贴原文吧:It is possible to do an I/O operation that does not result in an I/O completion
    packet being sent to the completion port and instead uses the old
    signaled event object mechanism. To do so, set up an OVERLAPPED structure
    with a valid hEvent manual-reset event object, then set the low-order bit
    of the handle to 1. Although
      

  7.   

    break,是因为你的错误的原因不是你列出的三种。
    具体那种要调试和查文档的。
      

  8.   

    简单看了你的代码,你确定 &pCntx->ovIn 这句中,调用IssueRead时,OVERLAPPED结构填充的正确吗?另外这种简单的问题,有源代码直接就调试了,别人没代码,也没功夫,更重要的是也没有你写这个程序时的思路(和环境),只能指明你的问题所在,还得靠自己。
    比如那个break,你就那么武断的说break出来了?没想一下为什么break?肯定是没进入if语句呗。
      

  9.   

    估计应该是 if (i <= 5) 之类的
      

  10.   

    。。我说,能淡定的回帖嘛首先不看代码,不对对同一个socket进行多次readfile的, 难道不对吗?必须受到数据后,才能够再次readfile这个没有争议吧?回头看代码:成功自然 return ,然后去 getqueuedcompletionstatus里拿收据。如果是error_io_pending,那么也是return, 因为也可以从 getqueuedcompletionstatus里拿数据。如果是其他错误的话,那么没法拿数据了,此时是否需要再次readfile呢?就这么个简单的道理,如果需要, 我们可以continue,因为是在一个while循环里啊,如果不需要直接break就行了。i==5 之类 无稽之谈
      

  11.   

    呵呵,如果那说得过分了,抱歉,请指正.今后注意.应该是楼上回复的,i <=5吧.
    另外咱哥俩有没仇,怎么不淡定呢?对不?我也是半瓶水,抱歉了.
      

  12.   

    我也在看这本术
    关于auto-reset event的说法似乎也有问题
    侯捷说auto-reset event会丢失
    但msdn是这么说的:
    When the state of an auto-reset event object is signaled, it remains signaled until a single waiting thread is released; the system then automatically resets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled.