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啊?需不需要, 我查了不少资料,不知道这个法子,作者是从哪里搞来的。
解决方案 »
- IoConnectInterrupt中的Vector如何获得?
- vs2008 如何为一个类添加 add windows message handle??
- 如何判断IE的窗口是第一次打开?
- 哪位给我个STIP的matlab代码或者代码链接?
- 谁有vc++技术内幕中文版发我,
- atof的问题
- 如何建立一个vb中可以调用的dll
- 在线等!高手进——Modem问题
- installshield如何安装硬件的驱动程序(ini,sys文件)
- 求dxsdk_sum2004_extras.exe or dxsdk_oct2004_extras.exe 有的私聊
- GetWindowText 获取中文标题问题。
- OnLButtonDown和焦点问题。
2是表明这个socket不加入IO队列(创建一个Event,然后 (句柄| 0x01)),这个在windows 核心编程中提及。
// 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呀,查下书吧,可能是同步的方式。搞这个得看书呢,记得不太清了。
你说的不对,直接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
具体那种要调试和查文档的。
比如那个break,你就那么武断的说break出来了?没想一下为什么break?肯定是没进入if语句呗。
另外咱哥俩有没仇,怎么不淡定呢?对不?我也是半瓶水,抱歉了.
关于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.