NamHyuk Im
NamHyuk Im

Reputation: 11

wsasend lpnumberofbytesSent

I am using wsasend on an IOCP structured server. There is one problem.

wsabuf [bufcount - 1] .buf = pPacket-> GetPacketBufferPtr ();
wsabuf [bufcount - 1] .len = (int) pPacket-> Get_PacketSize ();
iSendSize + = wsabuf [bufcount - 1] .len;
bufcount ++;
int retval = WSASend (pSession-> socket, wsabuf, bufcount-1, & sendbytes,flag, & pSession-> overlapped_Send, NULL);
if (retval == SOCKET_ERROR)
{

    if (WSAGetLastError ()! = WSA_IO_PENDING)
    {
      ......
    }
}
if (retval == 0)
{
    if (sendbytes! = iSendSize)
    {
       ........
    }
}
.....

In the code above, I save the packet to send to wsabuf and I send it through wsasend. And finally, I compared sendbytes and iSendSize . By the way, sendbytes and iSendSize are Different. I do not know why.

Upvotes: 1

Views: 210

Answers (1)

RbMm
RbMm

Reputation: 33754

the actual number of transferred bytes returned from driver, only when operation is completed. io subsystem copy this value to IO_STATUS_BLOCK.Information transmitted to io operation. as result user get back this value. but of course only after operation is completed.

win32 api use OVERLAPPED in place IO_STATUS_BLOCK - reinterpret cast OVERLAPPED to IO_STATUS_BLOCK and pass this pointer to kernel. so InternalHigh will be containing actual number of transferred bytes, but only after operation will be completed (in case error synchronous returned - io subsystem not fill this field, so it value undefined on error. by sense of course 0).

WSASend get value (after call to kernel) from OVERLAPPED.InternalHigh and if lpNumberOfBytesSent not 0 - copy it here. if you use synchronous socket handle - at this moment io operation already will be completed (io subsystem internal wait for this, before return to caller) and valid value from OVERLAPPED.InternalHigh will be copied to *lpNumberOfBytesSent

in code this will be look like

if (!lpOverlapped)
{
    OVERLAPPED Overlapped = {};
    lpOverlapped = &Overlapped;
}

ZwDeviceIoControlFile(.. reinterpret_cast<IO_STATUS_BLOCK*>(lpOverlapped) ..)

if (lpNumberOfBytesSent)
{
  *lpNumberOfBytesSent = (ULONG)lpOverlapped->InternalHigh;
}

in case asynchronous socket handle, operation usually yet not finished after return from kernel. as result lpOverlapped->InternalHigh yet not filled with correct numbers of bytes. and

*lpNumberOfBytesSent = (ULONG)lpOverlapped->InternalHigh;

got incorrect (undefined, if you and system not init it, say to 0) result.

conclusion - you can not use sendbytes for asynchronous io operation. what here is undefined. you can and need got this value when io is completed. how you got it already depend from how you notified about completion.

  • if you use BindIoCompletionCallback - you got it in FileIOCompletionRoutine in dwNumberOfBytesTransfered argument
  • if you use CreateThreadpoolIo- you got it in IoCompletionCallback in NumberOfBytesTransferred argument
  • if you use own IOCP and GetQueuedCompletionStatus - you got back pointer to your lpOverlapped used in call to WSASend (or some another io function - this is already your task determinate where this lpOverlapped used ) after operation was completed. at this point you can call GetOverlappedResult for this lpOverlapped (bWait you can set to any value - does not matter because operation already completed - the api will return immediately in any case without wait) and you got actual number of transferred bytes in lpNumberOfBytesTransferred. however GetOverlappedResult simply copy lpOverlapped->InternalHigh value to *lpNumberOfBytesTransferred so you can and direct, yourself use InternalHigh without call to GetOverlappedResult

Upvotes: 1

Related Questions