Reputation: 11
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
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.
BindIoCompletionCallback
- you got it in
FileIOCompletionRoutine
in dwNumberOfBytesTransfered
argumentCreateThreadpoolIo
- you got it in
IoCompletionCallback
in NumberOfBytesTransferred
argumentGetQueuedCompletionStatus
- 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