你们中的许多人都知道原始的“send()”不会将您要求的字节数写入线路。您可以轻松地使用指针和循环来确保您的数据已全部发送。
但是,在这种情况下,我看不到 WSASend() 和完成端口如何工作。它立即返回,您无法控制发送了多少(除了您可以在例程中访问的 lpLength )。如何解决?
您是否必须在例程中多次调用 WSASend() 才能获取所有数据?这似乎不是一个很大的缺点,特别是如果您希望以特定顺序输出数据并且多个线程访问例程?
你们中的许多人都知道原始的“send()”不会将您要求的字节数写入线路。您可以轻松地使用指针和循环来确保您的数据已全部发送。
但是,在这种情况下,我看不到 WSASend() 和完成端口如何工作。它立即返回,您无法控制发送了多少(除了您可以在例程中访问的 lpLength )。如何解决?
您是否必须在例程中多次调用 WSASend() 才能获取所有数据?这似乎不是一个很大的缺点,特别是如果您希望以特定顺序输出数据并且多个线程访问例程?
当您使用与一个和一个结构WSASend
相关联的套接字进行调用时,您可以有效地将数据传递给网络堆栈以进行发送。一旦网络堆栈不再需要您使用的数据缓冲区,网络堆栈将为您提供“完成”。此时,您可以自由地重用或释放用于数据缓冲区的内存。IOCP
OVERLAPPED
请注意,数据不太可能在生成完成时到达对等方,并且完成的生成意味着网络堆栈已获得缓冲区内容的所有权。
这与send
操作方式不同。在send
阻塞模式下,调用send
将阻塞,直到网络堆栈使用了您提供的所有数据。对于send
在非阻塞模式下的调用,网络堆栈从缓冲区中获取尽可能多的数据,然后返回给您使用的详细信息;这意味着您的某些数据已被使用。WSASend
通常,在您收到通知之前,您的所有数据都会被使用。
WSASend
由于资源限制或网络错误,重叠可能会失败。出现表明某些数据已发送但不是全部的失败是不常见的。通常它都发送好或根本没有发送。但是,可能会出现错误,这表明某些数据已被使用但不是全部。从这一点开始的方式取决于错误(临时资源限制或硬网络故障)以及WSASend
您在该套接字上挂起的其他 s 数量(零或非零)。如果您有临时资源错误并且没有其他未解决的问题,您只能尝试发送其余数据WSASend
调用此套接字;而且由于您不知道临时资源限制情况何时会过去,这使情况变得更加复杂......如果您曾经有临时资源限制导致部分发送并且您确实有其他WSASend
呼叫未决,那么您可能应该中止连接,因为您可能通过从该调用发送部分缓冲区WSASend
,然后发送后续WSASend
调用的全部(或部分)而使您的数据流出现乱码。
请注意,WSASend
在一个套接字上处理多个未完成的调用是 a) 有用且 b) 高效的。这是保持连接充分利用的唯一方法。但是,您应该注意WSASend
一次挂起多个重叠调用的内存和资源使用影响(请参阅此处),因为您正在有效地控制缓冲区的生命周期(以及您的内存和资源量)由于 TCP 流控制问题,代码使用)到对等方)。看看SIO_IDEAL_SEND_BACKLOG_QUERY
,SIO_IDEAL_SEND_BACKLOG_CHANGE
如果你想变得非常聪明......
WSASend()
在套接字接受所有请求的数据或发生错误之前,完成端口上不会通知您,以先发生者为准。它一直在后台工作,直到所有数据都被接受(或出错)。WSASend()
在它通知您之前,该缓冲区必须在内存中保持活动状态,但是您的代码可以在忙碌时继续执行其他操作。数据实际传输到对等方时没有通知。如果您需要,那么您必须在数据协议中实现 ACK,以便对等方在收到数据时通知您。
首先关于send
. 实际上可能会发生两种不同的事情,具体取决于套接字的配置方式。
如果套接字处于所谓的阻塞模式(默认) - 调用send
将阻塞调用线程,直到底层网络驱动程序消耗所有输入缓冲区。(请注意,这并不意味着数据已经到达对等方)。
如果套接字被转移到非阻塞模式 -如果底层驱动程序可能不会立即消耗所有输入,则调用send
将失败。在这种情况下的GetLastError
回报。WSAEWOULDBLOCK
应用程序应该等到它可以重试发送。应用程序应该从系统获取有关套接字状态更改的通知,而不是循环调用send
。诸如WSAEventSelect
或之类的函数WSAAsyncSelect
可用于此(以及 legacy select
)。
现在,有了 I/O 完成端口,WSASend
情况就有些不同了。当套接字与完成端口相关联时 - 它会自动转换为非阻塞模式。
如果调用WSASend
不能立即完成(即网络驱动程序不能消耗所有输入) -WSASend
返回错误并GetLastError
返回STATUS_PENDING
. 这实际上意味着异步操作已开始但尚未完成**。
也就是说,您不应该WSASend
重复调用,因为发送操作已经在进行中。当它完成时(无论成功与否),您都会在 I/O 完成端口上收到通知,但同时调用线程可以自由地做其他事情。