我建立使用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