【问题标题】:wsasend lpnumberofbytesSentwsasend lpnumberofbytesSent
【发布时间】:2018-06-02 12:52:53
【问题描述】:

我在 IOCP 结构化服务器上​​使用 wsasend。 有一个问题。

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)
    {
       ........
    }
}
.....

在上面的代码中,我保存了要发送到 wsabuf 的数据包,并通过 wsasend 发送它。 最后,我比较了 sendbytes 和 iSendSize 。 顺便说一句,sendbytes 和 iSendSize 是不同的。 我不知道为什么。

【问题讨论】:

  • From the documentation: "如果lpOverlapped 参数不是NULL,则将NULL 用于此参数(lpNumberOfBytesSent) 以避免潜在的错误结果。"
  • 如果使用异步io,一定不能使用(ignore)sendbytes,而是overlapped_Send.InternalHigh或者GetOverlappedResult返回的NumberOfBytesTransferred(其实就是简单的复制@987654330 @value to here) 操作完成时
  • @IgorTandetnik 文档有误。在带有 SP2 的 Windows XP 上,这将因访问冲突而崩溃,因为没有检查 lpNumberOfBytesSent 是否为 NULLWSASend 在 Windows XP 上的工作方式不同。它不会忽略 lpNumberOfBytesSent,即使它被设置为 NULL 并且该函数被称为重叠。

标签: visual-c++ iocp overlapped-io


【解决方案1】:

驱动程序返回的实际传输字节数,仅当操作完成时。 io子系统将此值复制到IO_STATUS_BLOCK.Information传送给io操作。结果用户取回了这个值。但当然只有在操作完成后。

win32 api 使用OVERLAPPED 代替IO_STATUS_BLOCK - 将OVERLAPPED 重新解释为IO_STATUS_BLOCK 并将此指针传递给内核。所以InternalHigh 将包含实际传输的字节数,但只有在操作完成之后(如果错误同步返回 - io 子系统未填充此字段,因此错误时它的值为 undefined。当然是 0)。

WSASendOVERLAPPED.InternalHigh 获取值(调用内核后),如果lpNumberOfBytesSent 不是0 - 将其复制到此处。如果您使用同步套接字句柄 - 此时 io 操作已经完成(io 子系统内部等待此,然后返回给调用者)并且来自 OVERLAPPED.InternalHigh 的有效值将被复制到 *lpNumberOfBytesSent

在代码中会是这样的

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

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

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

如果是异步套接字句柄,从内核返回后操作通常尚未完成。结果lpOverlapped-&gt;InternalHigh 尚未填充正确的字节数。和

*lpNumberOfBytesSent = (ULONG)lpOverlapped->InternalHigh;

得到不正确的(未定义,如果你和系统没有初始化它,说为 0)结果。

结论 - 你不能使用 sendbytes 进行异步 io 操作。这里是未定义的。 当 io 完成时,你可以并且需要得到这个值。你如何得到它已经取决于你如何通知完成。

  • 如果你使用BindIoCompletionCallback - 你得到它 FileIOCompletionRoutine in dwNumberOfBytesTransfered 论据
  • 如果你使用CreateThreadpoolIo- 你得到了它 IoCompletionCallbackNumberOfBytesTransferred 参数中
  • 如果你使用自己的 IOCPGetQueuedCompletionStatus - 你得到了 指向您的 lpOverlapped 的返回指针,用于调用 WSASend(或 另一个 io 函数 - 这已经是你的任务了 其中 lpOverlapped 使用)在操作完成后。在 这一点你可以打电话给GetOverlappedResult lpOverlapped (bWait 你可以设置为任何值 - 没关系,因为操作已经完成 - api 将返回 立即在任何情况下无需等待)并且您获得了实际数量 lpNumberOfBytesTransferred 中传输的字节。然而 GetOverlappedResult 只需复制 lpOverlapped-&gt;InternalHigh*lpNumberOfBytesTransferred,这样你就可以直接, 自己使用InternalHigh,无需致电GetOverlappedResult

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-08
    • 2021-08-05
    • 2023-03-11
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    相关资源
    最近更新 更多