Click to See Complete Forum and Search --> : WSARecv() for IOCP


keenlearner
July 2nd, 2007, 11:16 AM
I have problem about WSARecv() in IOCP , the second parameter of WSABUF, if my buffer length is less than the actual message size how can get the rest of the data ? just make another call to WSARecv() ? Thanks.

MikeAThon
July 2nd, 2007, 11:23 AM
Yes, simply call it again.

keenlearner
July 2nd, 2007, 11:35 AM
Thanks for the prompt reply, but when I called it again I get the dwBytesTransfered which is the second parameter of GetQueuedCompletionStatus as 0 . Also, after I called WSARecv() I never get the error WSAEMSGSIZE which tell message was too large to fit into the specified buffer. Is this message for UDP socket only ? because I am using TCP stream socket. How can I detect my specified buffer was not enough to receive the message ?

Naumaan
July 2nd, 2007, 12:08 PM
yes WSAEMSGSIZE is used for datagram socket. Check the return value of GetQueuedCompketionStatus It might helps you.
Return Values
If the function dequeues a completion packet for a successful I/O operation from the completion port, the return value is nonzero. The function stores information in the variables pointed to by the lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped parameters.

If *lpOverlapped is NULL and the function does not dequeue a completion packet from the completion port, the return value is zero. The function does not store information in the variables pointed to by the lpNumberOfBytes and lpCompletionKey parameters. To get extended error information, call GetLastError. If the function did not dequeue a completion packet because the wait timed out, GetLastError returns WAIT_TIMEOUT.

If *lpOverlapped is not NULL and the function dequeues a completion packet for a failed I/O operation from the completion port, the return value is zero. The function stores information in the variables pointed to by lpNumberOfBytes, lpCompletionKey, and lpOverlapped. To get extended error information, call GetLastError.

If a socket handle associated with a completion port is closed, GetQueuedCompletionStatus returns ERROR_SUCCESS, with *lpOverlapped non-NULL and lpNumberOfBytes equal zero

keenlearner
July 2nd, 2007, 12:48 PM
I have already check the return value of GetQueuedCompketionStatus, even if my WSABUF length used is less than the actual message when I called WSARecv(), the return value of GetQueuedCompketionStatus is NON-ZERO. This is my workerThread for IOCP, in case you want to view it. Thanks .

DWORD WINAPI workerThread(LPVOID lParam)
{
DWORD dwBytesTransfered = 0, recvByte = 0, flags = 0, sentByte = 0;
void *lpContext = NULL;
OVERLAPPED *pOverlapped = NULL;
LPPER_HANDLE_DATA lpHandleData = NULL;
int nResult;
WSABUF wsaBuf;
char buffer[MAX_BUFFER_LEN];
wsaBuf.len = MAX_BUFFER_LEN;
wsaBuf.buf = buffer;

while(1)
{
//printf("DEBUG %d\n", GetLastError());
nResult = GetQueuedCompletionStatus(g_hCompletionPort, &dwBytesTransfered,(LPDWORD)&lpContext, &pOverlapped, INFINITE);
lpHandleData = (LPPER_HANDLE_DATA) lpContext;

if(nResult == FALSE || ((nResult == TRUE) && (dwBytesTransfered == 0)))
{
printf("GetQueuedCompletionStatus ERROR : %d\n", GetLastError());
if(GetLastError() != 0) // application has completed successfully
continue;
}

printf("Bytes transfered/received : %d\n", dwBytesTransfered);
switch(lpHandleData->opCode)
{
case OP_READ:
memset(buffer, 0, MAX_BUFFER_LEN);
wsaBuf.buf = buffer;
wsaBuf.len = MAX_BUFFER_LEN;

if(WSARecv(lpHandleData->serverSocket, &wsaBuf, 1, &recvByte, &flags, &lpHandleData->ol, NULL) == SOCKET_ERROR)
if(WSAGetLastError() == WSA_IO_PENDING)
printf("WSARecv WSA_IO_PENDING\n");
else
printf("WSARecv ERROR : %d\n", WSAGetLastError());
lpHandleData->opCode = OP_WRITE;

break;

case OP_WRITE:
printf("flags : %d\n", flags);
printf("Data received : \n%s\n", wsaBuf.buf);


break;
case OP_CONNECT: // just connected to the server
printf("Connected\n");

//printf("DEBUG %d\n", GetLastError());
//memset(&wsaBuf, 0, sizeof(wsaBuf));
memset(buffer, 0, sizeof(buffer));
memset(&lpHandleData->ol, 0, sizeof(lpHandleData->ol));
//\r\nConnection: close
sprintf(buffer, "GET / HTTP/1.1\r\nConnection: close\r\nHost: %s\r\n\r\n", lpHandleData->host);
wsaBuf.buf = buffer;
wsaBuf.len = strlen(buffer);

lpHandleData->opCode = OP_READ;
if(WSASend(lpHandleData->serverSocket, &wsaBuf, 1, &sentByte, flags, &lpHandleData->ol, FALSE) == SOCKET_ERROR)
{
if(WSAGetLastError() == WSA_IO_PENDING)
printf("WSASend WSA_IO_PENDING\n");
else printf("WSASend ERROR : %d\n", WSAGetLastError());
}
else printf("WSASend complete immediately.\n");
break;
}
}

return 0;
}

MikeAThon
July 2nd, 2007, 01:15 PM
Thanks for the prompt reply, but when I called it again I get the dwBytesTransfered which is the second parameter of GetQueuedCompletionStatus as 0 .
A zero for dwBytesTransferred means that the connection was closed by the peer. You should call closesocket() and cloe the socket.
Also, after I called WSARecv() I never get the error WSAEMSGSIZE which tell message was too large to fit into the specified buffer. Is this message for UDP socket only ?
As Nauman has indicated, this error is for UDP only. You will not see it for TCP.
because I am using TCP stream socket. How can I detect my specified buffer was not enough to receive the message ?
There's no need to "detect" anything. If you are expecting more data, simply call WSARecv() again.

Make certain that you are expecting more data, however. You should be using some kind of protocol, that you impose at the application level, to tell the recipient how much data he should expect to receive.

Mike

MikeAThon
July 2nd, 2007, 01:26 PM
I just noticed that your worker thread uses the same "buffer" for both sends and recvs. That's an incorrect architecture for IOCP. You need to use a separate, unique buffer for each send and recv, commonly referred-to as a "per I/O buffer", and normally defined inside of a per-I/O structure. A pointer to this structure is returned to you in the lpOverlapped parameter of GetQueuedCompletionStatus.

Mike

keenlearner
July 2nd, 2007, 09:08 PM
Now the WSARecv() return the subsequent data after the subsequent call, and you are right I should have WSABUF in the PER_IO_DATA sructure. Thanks so much.

lebron232323
November 9th, 2010, 05:58 PM
Hi! I found this thread because i have a similar probem. I need change traffic on fly and i dicide use lsp to achive that! So as example i use microsoft example ftp://ftp.microsoft.com/bussys/Winsock/Winsock2/layered.zip
But i have a problem with reallocating lpBuffers variable in WSPRecv function to add in some data.
How i can do that and can you give me your implementation of y code which posted in this thread?