DWORD WINAPI CIOCPServer::_WorkerThreadProc(LPVOID lpParam)
{
#ifdef _DEBUG
::OutputDebugString(" WorkerThread 启动... \n");
#endif // _DEBUG
CIOCPServer *pThis = (CIOCPServer*)lpParam;
CIOCPBuffer *pBuffer;
DWORD dwKey;
DWORD dwTrans;
LPOVERLAPPED lpol;
while(TRUE)
{
// 在关联到此完成端口的所有套节字上等待I/O完成
BOOL bOK = ::GetQueuedCompletionStatus(pThis->m_hCompletion,
&dwTrans, (LPDWORD)&dwKey, (LPOVERLAPPED*)&lpol, WSA_INFINITE);
if(dwTrans == -1) // 用户通知退出
{
#ifdef _DEBUG
::OutputDebugString(" WorkerThread 退出 \n");
#endif // _DEBUG
::ExitThread(0);
}
pBuffer = CONTAINING_RECORD(lpol, CIOCPBuffer, ol);
int nError = NO_ERROR;
if(!bOK) // 在此套节字上有错误发生
{
SOCKET s;
if(pBuffer->nOperation == OP_ACCEPT)
{
s = pThis->m_sListen;
}
else
{
if(dwKey == 0)
break;
s = ((CIOCPContext*)dwKey)->s;
}
DWORD dwFlags = 0;
if(!::WSAGetOverlappedResult(s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags))
{
nError = ::WSAGetLastError();
}
}
pThis->HandleIO(dwKey, pBuffer, dwTrans, nError);
}
#ifdef _DEBUG
::OutputDebugString(" WorkerThread 退出 \n");
#endif // _DEBUG
return 0;
}
其中pBuffer是per-IO数据,HandleIO处理完成的请求,投递新的请求,释放完成的per-I/O和per-handl数据。
我的问题是GetQueuedCompletionStatus的返回值不太了解,对以下段代码不太理解:
if(!bOK)
{
这里整段的代码不太理解,各位高手帮忙详细解释一下啊 !!!
}
拜托了,刚开始看完成端口,郁闷了一下午了!!!
10 个解决方案
#1
好象你看的是王艳平那本书的代码,那书上讲的很清楚的,这个代码也有很好的参考价值,你投递IO请求后GetQueuedCompletionStatus回返回他们的完成状态,比如read事件,调用GetQueuedCompletionStatus返回时,它会告诉你收到了多少数据,数据就存放在你提供给他的缓冲区中,提交write操作后,GetQueuedCompletionStatus返回时,它又告诉你已经完成发送了多少数据,返回的发送字节数在dwTrans这个参数里得知,这样你就可以根据per-handl里记录的数据结构判断是否帮你发完提交的数据,没完可以考虑在次提交write(根据你的应用来)
#2
你说的太对了,我是看的那本书,不过你说的我似乎都明白,但是我问的是这段代码:
if(!bOK)
{
这里整段的代码不太理解,各位高手帮忙详细解释一下啊 !!!
}
麻烦你给我解释一下,这里的
if()
...... //1
else
...... //2
if(!::WSAGetOverlappedResult(s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags)) //3
{
nError = ::WSAGetLastError();
}
这三处注释我是在不明白,麻烦您帮我解释一下。
if(!bOK)
{
这里整段的代码不太理解,各位高手帮忙详细解释一下啊 !!!
}
麻烦你给我解释一下,这里的
if()
...... //1
else
...... //2
if(!::WSAGetOverlappedResult(s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags)) //3
{
nError = ::WSAGetLastError();
}
这三处注释我是在不明白,麻烦您帮我解释一下。
#3
还有什么不明白? 1和2就是判断完成的操作,一般有accept(接受连接),read(有数据可读),write(可以写了)
这里 我估计你不明白怎么得到CIOCPBuffer这个数据结构,你要注意了,
CIOCPBuffer的第一个字段就是个overlap结构,也就是CIOCPBuffer这个结构体的首地址,把这个首地址提交,这样在GetQueuedCompletionStatus返回时就能获得CIOCPBuffer表示的结构了,是充分利用这个技巧才能够拓宽表示内容
这里 我估计你不明白怎么得到CIOCPBuffer这个数据结构,你要注意了,
CIOCPBuffer的第一个字段就是个overlap结构,也就是CIOCPBuffer这个结构体的首地址,把这个首地址提交,这样在GetQueuedCompletionStatus返回时就能获得CIOCPBuffer表示的结构了,是充分利用这个技巧才能够拓宽表示内容
#4
你为什么不看清楚我的问题呢,你说的这些包括这些技巧我还是差不多理解的。
我的意思是 我不明白这段代码:
请高手回答我的三个问题
我的意思是 我不明白这段代码:
if(!bOK) // 在此套节字上有错误发生
{
SOCKET s;
if(pBuffer->nOperation == OP_ACCEPT) //1.这里是第一处不明白,为什么这样,得到s做什么
{
s = pThis->m_sListen;
}
else
{
if(dwKey == 0) //2.这里又是为什么:1.用意和在;2.为什么又要得到s
break;
s = ((CIOCPContext*)dwKey)->s;
}
DWORD dwFlags = 0;
if(!::WSAGetOverlappedResult(s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags))
{ //3.对这个得到的s调用WSAGetOverlappedResult作用。 nError = ::WSAGetLastError();
}
}
请高手回答我的三个问题
#5
我是楼主,看上面的问题啊
#6
得到s(SOCKET类型)就是为了调用
WSAGetOverlappedResult取检测完成状态。当accept的时候,检测监听(Listen)Socket,其它情况检查通讯(Communication)Socket。更多的信息建议查看
MSDN.
其实这个写法不是必要的,只是个人的一种检测错误源或者相关socket状态的写法或手段。
其实这个写法不是必要的,只是个人的一种检测错误源或者相关socket状态的写法或手段。
#7
僵哥,可以在问几个小问题吗?
1.完成端口完全可以在前一个io未完成前投递多个io操作,比如WSASend,
io投递后只不过缩投递的缓冲区会被系统锁定,这也就需要很大的内存,之所以说它比重叠io多占用系统资源
锁定谁的缓冲区?
2.完成例程、完成端口提供了比较好的解决方案,只不过对于完成例程
来说,初次使用的朋友可能感觉不是很好用,其实它也可以实现很高的性能解决方案,因为他本身就是通过用户APC来
实现;最后一个是完成端口通知,相对于完成例程来说,它建立多工作线程来监视多个socket事件更加容易。
这个完成端口和完成例程不是一个概念吗?
1.完成端口完全可以在前一个io未完成前投递多个io操作,比如WSASend,
io投递后只不过缩投递的缓冲区会被系统锁定,这也就需要很大的内存,之所以说它比重叠io多占用系统资源
锁定谁的缓冲区?
2.完成例程、完成端口提供了比较好的解决方案,只不过对于完成例程
来说,初次使用的朋友可能感觉不是很好用,其实它也可以实现很高的性能解决方案,因为他本身就是通过用户APC来
实现;最后一个是完成端口通知,相对于完成例程来说,它建立多工作线程来监视多个socket事件更加容易。
这个完成端口和完成例程不是一个概念吗?
#8
1.锁定的是你WSASend/WSASendTo/WSARecv/WSARecvFrom投递时给的WSABUF结构所指向的内存,其实还有核心内存的占用,而核心内存的过度占用才是影响性能的根本,至于占用系统资源,当出现不足的时候自然也就在应用层体现出来了。
2.不知道这是谁写的,要不你问问写这段话的人吧。相关重叠I/O的几种应用方式,我已经在你的贴子当中进行了列举,这里就不再重复。
#9
需要注意的是重叠I/O是一种I/O模型,相当于一种异步作业。而完成端口只是一种异步作业的完成通知模型。两者完成的是不同的业务内容。只是把他们结合起来可以更方便地实现我们的业务逻辑。对于要求系统主动实现的完成端口通知模型,那么这些操作就依赖于重叠I/O模型,或者说必须基于重叠I/O。
#10
up
#1
好象你看的是王艳平那本书的代码,那书上讲的很清楚的,这个代码也有很好的参考价值,你投递IO请求后GetQueuedCompletionStatus回返回他们的完成状态,比如read事件,调用GetQueuedCompletionStatus返回时,它会告诉你收到了多少数据,数据就存放在你提供给他的缓冲区中,提交write操作后,GetQueuedCompletionStatus返回时,它又告诉你已经完成发送了多少数据,返回的发送字节数在dwTrans这个参数里得知,这样你就可以根据per-handl里记录的数据结构判断是否帮你发完提交的数据,没完可以考虑在次提交write(根据你的应用来)
#2
你说的太对了,我是看的那本书,不过你说的我似乎都明白,但是我问的是这段代码:
if(!bOK)
{
这里整段的代码不太理解,各位高手帮忙详细解释一下啊 !!!
}
麻烦你给我解释一下,这里的
if()
...... //1
else
...... //2
if(!::WSAGetOverlappedResult(s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags)) //3
{
nError = ::WSAGetLastError();
}
这三处注释我是在不明白,麻烦您帮我解释一下。
if(!bOK)
{
这里整段的代码不太理解,各位高手帮忙详细解释一下啊 !!!
}
麻烦你给我解释一下,这里的
if()
...... //1
else
...... //2
if(!::WSAGetOverlappedResult(s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags)) //3
{
nError = ::WSAGetLastError();
}
这三处注释我是在不明白,麻烦您帮我解释一下。
#3
还有什么不明白? 1和2就是判断完成的操作,一般有accept(接受连接),read(有数据可读),write(可以写了)
这里 我估计你不明白怎么得到CIOCPBuffer这个数据结构,你要注意了,
CIOCPBuffer的第一个字段就是个overlap结构,也就是CIOCPBuffer这个结构体的首地址,把这个首地址提交,这样在GetQueuedCompletionStatus返回时就能获得CIOCPBuffer表示的结构了,是充分利用这个技巧才能够拓宽表示内容
这里 我估计你不明白怎么得到CIOCPBuffer这个数据结构,你要注意了,
CIOCPBuffer的第一个字段就是个overlap结构,也就是CIOCPBuffer这个结构体的首地址,把这个首地址提交,这样在GetQueuedCompletionStatus返回时就能获得CIOCPBuffer表示的结构了,是充分利用这个技巧才能够拓宽表示内容
#4
你为什么不看清楚我的问题呢,你说的这些包括这些技巧我还是差不多理解的。
我的意思是 我不明白这段代码:
请高手回答我的三个问题
我的意思是 我不明白这段代码:
if(!bOK) // 在此套节字上有错误发生
{
SOCKET s;
if(pBuffer->nOperation == OP_ACCEPT) //1.这里是第一处不明白,为什么这样,得到s做什么
{
s = pThis->m_sListen;
}
else
{
if(dwKey == 0) //2.这里又是为什么:1.用意和在;2.为什么又要得到s
break;
s = ((CIOCPContext*)dwKey)->s;
}
DWORD dwFlags = 0;
if(!::WSAGetOverlappedResult(s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags))
{ //3.对这个得到的s调用WSAGetOverlappedResult作用。 nError = ::WSAGetLastError();
}
}
请高手回答我的三个问题
#5
我是楼主,看上面的问题啊
#6
得到s(SOCKET类型)就是为了调用
WSAGetOverlappedResult取检测完成状态。当accept的时候,检测监听(Listen)Socket,其它情况检查通讯(Communication)Socket。更多的信息建议查看
MSDN.
其实这个写法不是必要的,只是个人的一种检测错误源或者相关socket状态的写法或手段。
其实这个写法不是必要的,只是个人的一种检测错误源或者相关socket状态的写法或手段。
#7
僵哥,可以在问几个小问题吗?
1.完成端口完全可以在前一个io未完成前投递多个io操作,比如WSASend,
io投递后只不过缩投递的缓冲区会被系统锁定,这也就需要很大的内存,之所以说它比重叠io多占用系统资源
锁定谁的缓冲区?
2.完成例程、完成端口提供了比较好的解决方案,只不过对于完成例程
来说,初次使用的朋友可能感觉不是很好用,其实它也可以实现很高的性能解决方案,因为他本身就是通过用户APC来
实现;最后一个是完成端口通知,相对于完成例程来说,它建立多工作线程来监视多个socket事件更加容易。
这个完成端口和完成例程不是一个概念吗?
1.完成端口完全可以在前一个io未完成前投递多个io操作,比如WSASend,
io投递后只不过缩投递的缓冲区会被系统锁定,这也就需要很大的内存,之所以说它比重叠io多占用系统资源
锁定谁的缓冲区?
2.完成例程、完成端口提供了比较好的解决方案,只不过对于完成例程
来说,初次使用的朋友可能感觉不是很好用,其实它也可以实现很高的性能解决方案,因为他本身就是通过用户APC来
实现;最后一个是完成端口通知,相对于完成例程来说,它建立多工作线程来监视多个socket事件更加容易。
这个完成端口和完成例程不是一个概念吗?
#8
1.锁定的是你WSASend/WSASendTo/WSARecv/WSARecvFrom投递时给的WSABUF结构所指向的内存,其实还有核心内存的占用,而核心内存的过度占用才是影响性能的根本,至于占用系统资源,当出现不足的时候自然也就在应用层体现出来了。
2.不知道这是谁写的,要不你问问写这段话的人吧。相关重叠I/O的几种应用方式,我已经在你的贴子当中进行了列举,这里就不再重复。
#9
需要注意的是重叠I/O是一种I/O模型,相当于一种异步作业。而完成端口只是一种异步作业的完成通知模型。两者完成的是不同的业务内容。只是把他们结合起来可以更方便地实现我们的业务逻辑。对于要求系统主动实现的完成端口通知模型,那么这些操作就依赖于重叠I/O模型,或者说必须基于重叠I/O。
#10
up