WSARecv() WSABUF less than the actual message

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • eagerlearner
    New Member
    • Jul 2007
    • 29

    WSARecv() WSABUF less than the actual message

    I am programming windows socket using IO completion port strategy. I have problem about WSARecv() in IO completion port , the second parameter of WSABUF, if my buffer length is less than the actual message size how can get the rest of the data ? When I called the WSARec() once again, I get the received bytes return by GetQueuedComple tionStatus as zero. Thanks.
  • weaknessforcats
    Recognized Expert Expert
    • Mar 2007
    • 9214

    #2
    I read that the first argument is an array of WSABUF structures and the second argument is the number of elements in that array.

    The WSABUF struct has a pointer to an array and an unsigned int for the length of the array. Apparantly, you can pre-allocate a bunch of buffers and put the addresses of those buffers and their lengths into the array of WSABUF used as the first argument.

    I presume you will need to pre-allocate sufficient memory.

    WSARecv .

    Comment

    • eagerlearner
      New Member
      • Jul 2007
      • 29

      #3
      Thanks for the prompt reply.
      The size or length of the data that I want to receive is UNKNOWN, it is a client requesting for website from the web server. So if I pre-allocate the WSABUF as big as possible, there might be circumstances that will exceed this value. So that's why I need ways to detect the specified WSABUF is less than the actual message that I am receiving from the server. If I have received a portion of message, how can I receive the rest of the message ?
      You can see my workerThread of the IOCP.

      I have already check the return value of GetQueuedCompke tionStatus, even if my WSABUF length used is less than the actual message when I called WSARecv(), the return value of GetQueuedCompke tionStatus is NON-ZERO. This is my workerThread for IOCP, in case you want to view it. Thanks .
      Code:
      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;
      }

      Comment

      • weaknessforcats
        Recognized Expert Expert
        • Mar 2007
        • 9214

        #4
        If WSARecv() returns with WSAEMSGSIZE you did not get all of the message. If your WSARecv() call has the MSG_PARTIAL flag set, and your provider supports MSG_PARTIAL, then you can retreive the rest of the message on subsequent WSARecv() calls.

        Currently, you have no flags set.

        Comment

        • eagerlearner
          New Member
          • Jul 2007
          • 29

          #5
          Thanks, now I am clear about MSG_PARTIAL, it's only used for UDP socket only. while I am using TCP stream socket.

          Comment

          • weaknessforcats
            Recognized Expert Expert
            • Mar 2007
            • 9214

            #6
            So you can use the recv() call. Here you specify your buffer length and if the meessage is too long, it will be retained by the sender until you call again with a larger buffer. In this case recv() returns with a WSAEMSGSIZE error.

            recv().

            Comment

            Working...