我建立使用BindIoCompletionCallback一个Visual C++的WinSock TCP服务器,它工作正常接收和发送数据,但我找不到检测超时的好方法:setsockopt的/ SO_RCVTIMEO/SO_SNDTIMEO有对非阻塞套接字没有影响,如果对等体没有发送任何数据,则根本不调用CompletionRoutine。如何检测的WinSock TCP超时与BindIoCompletionCallback
我在考虑使用带有OVERLAPPED的hEvent字段的RegisterWaitForSingleObject,这可能会工作,但是完全不需要CompletionRoutine,我还在使用IOCP吗?如果我仅使用RegisterWaitForSingleObject而不使用BindIoCompletionCallback,是否有性能问题?
更新:代码示例:
我第一次尝试:
bool CServer::Startup() {
SOCKET ServerSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
WSAEVENT ServerEvent = WSACreateEvent();
WSAEventSelect(ServerSocket, ServerEvent, FD_ACCEPT);
......
bind(ServerSocket......);
listen(ServerSocket......);
_beginthread(ListeningThread, 128 * 1024, (void*) this);
......
......
}
void __cdecl CServer::ListeningThread(void* param) // static
{
CServer* server = (CServer*) param;
while (true) {
if (WSAWaitForMultipleEvents(1, &server->ServerEvent, FALSE, 100, FALSE) == WSA_WAIT_EVENT_0) {
WSANETWORKEVENTS events = {};
if (WSAEnumNetworkEvents(server->ServerSocket, server->ServerEvent, &events) != SOCKET_ERROR) {
if ((events.lNetworkEvents & FD_ACCEPT) && (events.iErrorCode[FD_ACCEPT_BIT] == 0)) {
SOCKET socket = accept(server->ServerSocket, NULL, NULL);
if (socket != SOCKET_ERROR) {
BindIoCompletionCallback((HANDLE) socket, CompletionRoutine, 0);
......
}
}
}
}
}
}
VOID CALLBACK CServer::CompletionRoutine(__in DWORD dwErrorCode, __in DWORD dwNumberOfBytesTransfered, __in LPOVERLAPPED lpOverlapped) // static
{
......
BOOL res = GetOverlappedResult(......, TRUE);
......
}
class CIoOperation {
public:
OVERLAPPED Overlapped;
......
......
};
bool CServer::Receive(SOCKET socket, PBYTE buffer, DWORD length, void* context)
{
if (connection != NULL) {
CIoOperation* io = new CIoOperation();
WSABUF buf = {length, (PCHAR) buffer};
DWORD flags = 0;
if ((WSARecv(Socket, &buf, 1, NULL, &flags, &io->Overlapped, NULL) != 0) && (GetLastError() != WSA_IO_PENDING)) {
delete io;
return false;
} else return true;
}
return false;
}
正如我所说的,它如果客户端实际发送数据给我,“接收”工作正常,不堵,CompletionRoutine了所谓的数据接收,但这里有一个问题,如果客户端没有向我发送任何数据,我怎么能在超时后放弃?
由于setsockopt的/ SO_RCVTIMEO/SO_SNDTIMEO不会帮助在这里,我想我应该在重叠stucture的IO完成时会发出信号使用hEvent领域,但对一个WaitForSingleObject的/ WSAWaitForMultipleEvents将阻止接收呼叫,我希望接收总是立即返回,所以我使用了RegisterWaitForSingleObject和WAITORTIMERCALLBACK。它工作,在超时后调用回调,或者IO完成,但是现在对任何单个IO操作,CompletionRoutine和WaitOrTimerCallback有两个回调:如果IO完成,它们将被同时调用,如果IO没有完成,WaitOrTimerCallback将被调用,然后我调用CancelIoEx,这会导致CompletionRoutine被调用,并带有一些ABORTED错误,但这是一个竞争条件,也许IO将在我取消它之前完成,然后... blahblah,一切都很复杂。
然后我意识到我不实际需要BindIoCompletionCallback和CompletionRoutine可言,从WaitOrTimerCallback做的一切,它可以工作,但这里是一个有趣的问题,我想首先建立一个基于IOCP-Winsock的服务器,并认为BindIoCompletionCallback是最简单的方法来做到这一点,使用Windows自身提供的线程池,现在我终于与没有IOCP代码的服务器?它仍然是IOCP?或者我应该忘记BindIoCompletionCallback并构建自己的IOCP线程池实现?为什么?
你在用什么语言工作?你能提供一个有限的代码示例吗? – 2011-12-31 06:57:08
你可能想看看这段代码:http://www.codeproject.com/KB/IP/iocp_server_client.aspx?msg = 1133926 Jeffrey Richter的“微软Windows 2000编程服务器端应用程序”的旧副本目前在其他地方,所以我不能给你任何帮助:( – paulsm4 2011-12-31 06:58:56
好吧,它的Visual C++,我会更新问题 – WalkingCat 2011-12-31 08:04:37