фактическое количество переданных байтов, возвращаемое драйвером только после завершения операции. io скопируйте это значение в IO_STATUS_BLOCK.Information
передается операции ввода-вывода. в результате пользователь возвращает это значение. но, конечно, только после завершения операции.
win32 API используйте OVERLAPPED
вместо IO_STATUS_BLOCK
— переинтерпретировать приведение OVERLAPPED
к IO_STATUS_BLOCK
и передать этот указатель ядру. поэтому InternalHigh
будет содержать фактическое количество переданных байтов, но только после завершения операции (в случае возврата ошибки синхронного - подсистема io не заполнит это поле, поэтому его значение не определено при ошибке. по смыслу, конечно, 0).
WSASend
получить значение (после обращения к ядру) из OVERLAPPED.InternalHigh
и если lpNumberOfBytesSent
не 0 - скопировать сюда. если вы используете синхронный дескриптор сокета - в этот момент операция ввода-вывода уже будет завершена (внутреннее ожидание этого подсистемы ввода-вывода, прежде чем вернуться к вызывающей стороне), и действительное значение из OVERLAPPED.InternalHigh
будет скопировано в *lpNumberOfBytesSent
в коде это будет выглядеть
if (!lpOverlapped)
{
OVERLAPPED Overlapped = {};
lpOverlapped = &Overlapped;
}
ZwDeviceIoControlFile(.. reinterpret_cast<IO_STATUS_BLOCK*>(lpOverlapped) ..)
if (lpNumberOfBytesSent)
{
*lpNumberOfBytesSent = (ULONG)lpOverlapped->InternalHigh;
}
в случае обработки асинхронного сокета операция обычно еще не завершена после возврата из ядра. в результате lpOverlapped->InternalHigh
еще не заполнено правильными номерами байтов. и
*lpNumberOfBytesSent = (ULONG)lpOverlapped->InternalHigh;
получил неверный (неопределенный, если вы и система не инициализируете его, скажем, 0) результат.
вывод - нельзя использовать sendbytes
для асинхронной операции ввода-вывода. что здесь не определено. вы можете и должны получить это значение когда ввод-вывод завершен. то, как вы его получили, уже зависит от того, как вы уведомили о завершении.
- если вы используете
BindIoCompletionCallback
- вы получили его в FileIOCompletionRoutine
в аргументе dwNumberOfBytesTransfered
- если вы используете
CreateThreadpoolIo
- вы получили это в IoCompletionCallback
в аргументе NumberOfBytesTransferred
- если вы используете собственный IOCP и
GetQueuedCompletionStatus
— вы получили обратный указатель на ваш lpOverlapped
, используемый при вызове WSASend
(или какой-то другой функции ввода-вывода — это уже ваша задача определить, где этот lpOverlapped
используется ) после завершения операции. на этом этапе вы можете вызвать GetOverlappedResult
для этого lpOverlapped
(bWait
вы можете установить любое значение — не имеет значения, потому что операция уже завершена — в любом случае API вернется немедленно, без ожидания) и вы получили фактическое количество переданных байтов в lpNumberOfBytesTransferred
. однако GetOverlappedResult
просто скопируйте значение lpOverlapped->InternalHigh
в *lpNumberOfBytesTransferred
, чтобы вы могли и направить, сами используйте InternalHigh
без вызова GetOverlappedResult
person
RbMm
schedule
20.12.2017
NULL
для этого параметра (lpNumberOfBytesSent
), если параметрlpOverlapped
не равенNULL
, чтобы избежать потенциально ошибочных результатов. - person Igor Tandetnik   schedule 20.12.2017sendbytes
, ноoverlapped_Send.InternalHigh
или NumberOfBytesTransferred, возвращаемыеGetOverlappedResult
(это действительно просто копирует значениеInternalHigh
сюда), когда операция завершена - person RbMm   schedule 20.12.2017lpNumberOfBytesSent
NULL
или нет.WSASend
работает иначе в Windows XP. Он не игнорируетlpNumberOfBytesSent
, даже если он был установлен вNULL
и функция была вызвана как перекрывающаяся. - person a man in love   schedule 23.09.2019