codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
/* This example demonstrates two problems with WSARecv and IOCP on Vista and up. I'm using Windows 7 Ultimate, and it still occurs here. One problem occurs when using FILE_SKIP_COMPLETION_PORT_ON_SUCCESS and one is when it is not in use. This example runs fine on XP, obviously with USE_SKIP_FEATURE = 0. The example simply accepts a socket and reads from it as fast as possible. With USE_SKIP_FEATURE = 1, it eventually (5-30 seconds) gets a timeout from GetQueuedCompletionStatus, which should not occur. You should see this example die with: queueing new event event completion pending GQCS wait timeout? With USE_SKIP_FEATURE = 0, it quickly (1-5 seconds) gets a return value of 0 from WSARecv with lpNumberOfBytesRecvd = 0, indicating socket closure, which should not be true. You should see this example will die with: queueing new event event completed right away: 0 bytes eof MSDN says: http://msdn.microsoft.com/en-us/library/ms741688(VS.85).aspx "For byte streams, zero bytes having been read (as indicated by a zero return value to indicate success, and lpNumberOfBytesRecvd value of zero) indicates graceful closure and that no more bytes will ever be read." ... "Overlapped Socket I/O If an overlapped operation completes immediately, WSARecv returns a value of zero and the lpNumberOfBytesRecvd parameter is updated with the number of bytes received and the flag bits indicated by the lpFlags parameter are also updated." I recommend directing the output of this example to a file, to prevent the console from slowing down the the application and making the bug difficult to encounter. For the connecting and sending side, anything which connects to localhost port 27015 and sends as fast as it can should do. Here is a very simple python script: import socket s = socket.socket() s.connect(("localhost", 27015)) while 1: s.send(" " * 65536) In both cases the sender dies with: socket.error: [Errno 10054] An existing connection was forcibly closed by the remote host If there are any questions or obvious bugs, please contact me at: ghazel at gmail dot com */ #define WIN32_LEAN_AND_MEAN #include <stdio.h> #include "winsock2.h" #include "mswsock.h" #include "malloc.h" #include <windows.h> #define BUFSIZE 16384 #define MAX_PENDING 5 #define USE_SKIP_FEATURE 0 void main() { //---------------------------------------- // Declare and initialize variables WSADATA wsaData; HANDLE hCompPort; SOCKET ListenSocket, AcceptSocket; sockaddr_in service; sockaddr a_addr; int a_addrlen = sizeof(a_addr); printf("use skip feature: %d\n", USE_SKIP_FEATURE); //---------------------------------------- // Initialize Winsock int iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != NO_ERROR) { printf("Error at WSAStartup\n"); return; } //---------------------------------------- // Create a handle for the completion port hCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (u_long)0, 0); //---------------------------------------- // Create a listening socket ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { printf("Error at socket(): ListenSocket\n"); WSACleanup(); return; } //---------------------------------------- // Associate the listening socket with the completion port CreateIoCompletionPort((HANDLE)ListenSocket, hCompPort, (u_long)0, 0); //---------------------------------------- // Bind the listening socket to the local IP address // and port 27015 hostent* thisHost; char* ip; u_short port; port = 27015; thisHost = gethostbyname("localhost"); ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list); service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr(ip); service.sin_port = htons(port); if (bind(ListenSocket,(SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR) { printf("bind failed\n"); closesocket(ListenSocket); return; } //---------------------------------------- // Start listening on the listening socket if (listen( ListenSocket, 100 ) == SOCKET_ERROR) { printf("error listening\n"); } printf("Listening on address: %s:%d\n", ip, port); AcceptSocket = accept(ListenSocket, &a_addr, &a_addrlen); if (AcceptSocket == INVALID_SOCKET) { printf("accept failed\n"); return; } CreateIoCompletionPort((HANDLE)AcceptSocket, hCompPort, (u_long)0, 0); #if USE_SKIP_FEATURE if (!SetFileCompletionNotificationModes((HANDLE)AcceptSocket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { printf("SetFileCompletionNotificationModes failed! %d\n", GetLastError()); return; } #endif int pending_completions = 0; while (1) { DWORD bytes; DWORD key; DWORD rc; DWORD flags = 0; char buf[BUFSIZE]; WSABUF wsabuf; WSAOVERLAPPED *ov = (WSAOVERLAPPED *)malloc(sizeof(WSAOVERLAPPED)); memset(ov, 0, sizeof(WSAOVERLAPPED)); wsabuf.len = 16384; wsabuf.buf = buf; printf("queueing new event\n"); rc = WSARecv(AcceptSocket, &wsabuf, 1, &bytes, &flags, ov, 0); if (rc == SOCKET_ERROR) { rc = WSAGetLastError(); if (rc != WSA_IO_PENDING) { printf("WSARecv error (a): %d\n", rc); return; } pending_completions += 1; printf("event completion pending\n"); } else if (rc != 0) { printf("WSARecv error (b): %d\n", rc); return; } if (rc == 0) { #if USE_SKIP_FEATURE // no completion pending notice, because of FILE_SKIP_COMPLETION_PORT_ON_SUCCESS free(ov); #else // we still need to receive the completion notice, even though the event is complete pending_completions += 1; #endif printf("event completed right away: %u bytes\n", bytes); if (bytes == 0) { printf("eof\n"); return; } if (pending_completions < MAX_PENDING) { printf("currently pending: %u of %u\n", pending_completions, MAX_PENDING); continue; } } while (pending_completions) { WSAOVERLAPPED *ovp; rc = GetQueuedCompletionStatus(hCompPort, &bytes, &key, ((OVERLAPPED **)(&ovp)), 2000); if (!rc) { rc = GetLastError(); if (rc == WAIT_TIMEOUT) { printf("GQCS wait timeout?\n"); // Two seconds should be plenty, when the sender is local and just in a tight-loop. //continue; return; } printf("GQCS error: %d\n", rc); if (rc == ERROR_NETNAME_DELETED) { printf("eof\n"); } return; } pending_completions -= 1; printf("event complete: (%u bytes) pending: %u of %u\n", bytes, pending_completions, MAX_PENDING); free(ovp); } } }
Private
[
?
]
Run code
Submit